Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/soong/cc/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 14 kB image not shown  

Quelle  coverage.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cc

import (
 "strconv"

 "github.com/google/blueprint"

 "android/soong/android"
)

var (
 clangCoverageHostLdFlags = []string{
  "-Wl,--no-as-needed",
  "-Wl,--wrap,open",
 }
 clangContinuousCoverageFlags = []string{
  "-mllvm",
  "-runtime-counter-relocation",
 }
 clangCoverageCFlags = []string{
  "-Wno-frame-larger-than=",
 }
 clangCoverageCommonFlags = []string{
  "-fcoverage-mapping",
  "-Wno-pass-failed",
  "-D__ANDROID_CLANG_COVERAGE__",

  // Bug: http://b/408093589, http://b/396515430: LLVM change 4089763883 to
  // global merge regressed code coverage, marking previously covered lines
  // as uncovered.  Disable global merge until the regression is fixed.
  // -Wunused-command-line-argument needs to be disabled because
  // -mno-global-merge is reported as unused in LTO mode.
  "-mno-global-merge",
  "-Wno-unused-command-line-argument",
 }
 clangCoverageHWASanFlags = []string{
  "-mllvm",
  "-hwasan-globals=0",
 }
)

const profileInstrFlag = "-fprofile-instr-generate=/data/misc/trace/clang-%p-%m.profraw"

type CoverageProperties struct {
 Native_coverage *bool

 NeedCoverageVariant bool `blueprint:"mutated"`
 NeedCoverageBuild   bool `blueprint:"mutated"`

 CoverageEnabled   bool `blueprint:"mutated"`
 IsCoverageVariant bool `blueprint:"mutated"`
}

type coverage struct {
 Properties CoverageProperties

 // Whether binaries containing this module need --coverage added to their ldflags
 linkCoverage bool
}

func (cov *coverage) props() []interface{} {
 return []interface{}{&cov.Properties}
}

func getGcovProfileLibraryName(ctx ModuleContextIntf) string {
 // This function should only ever be called for a cc.Module, so the
 // following statement should always succeed.
 // LINT.IfChange
 if ctx.useSdk() {
  return "libprofile-extras_ndk"
 } else {
  return "libprofile-extras"
 }
}

func getClangProfileLibraryName(ctx ModuleContextIntf) string {
 if ctx.useSdk() {
  return "libprofile-clang-extras_ndk"
 } else if ctx.isCfiAssemblySupportEnabled() {
  return "libprofile-clang-extras_cfi_support"
 } else {
  return "libprofile-clang-extras"
 }
 // LINT.ThenChange(library.go)
}

func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
 if cov.Properties.NeedCoverageVariant && ctx.Device() {
  ctx.AddVariationDependencies([]blueprint.Variation{
   {Mutator: "link", Variation: "static"},
  }, CoverageDepTag, getGcovProfileLibraryName(ctx))
  ctx.AddVariationDependencies([]blueprint.Variation{
   {Mutator: "link", Variation: "static"},
  }, CoverageDepTag, getClangProfileLibraryName(ctx))
 }
 return deps
}

func EnableContinuousCoverage(ctx android.BaseModuleContext) bool {
 return ctx.DeviceConfig().ClangCoverageContinuousMode()
}

func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
 clangCoverage := ctx.DeviceConfig().ClangCoverageEnabled()
 gcovCoverage := ctx.DeviceConfig().GcovCoverageEnabled()

 if !gcovCoverage && !clangCoverage {
  return flags, deps
 }

 if cov.Properties.CoverageEnabled {
  cov.linkCoverage = true

  if gcovCoverage {
   flags.GcovCoverage = true
   flags.Local.CommonFlags = append(flags.Local.CommonFlags, "--coverage", "-O0")

   // Override -Wframe-larger-than and non-default optimization
   // flags that the module may use.
   flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0")
  } else if clangCoverage {
   flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag)
   flags.Local.CommonFlags = append(flags.Local.CommonFlags, clangCoverageCommonFlags...)
   // Override -Wframe-larger-than.  We can expect frame size increase after
   // coverage instrumentation.
   flags.Local.CFlags = append(flags.Local.CFlags, clangCoverageCFlags...)
   if EnableContinuousCoverage(ctx) {
    flags.Local.CommonFlags = append(flags.Local.CommonFlags, clangContinuousCoverageFlags...)
   }

   // http://b/248022906, http://b/247941801  enabling coverage and hwasan-globals
   // instrumentation together causes duplicate-symbol errors for __llvm_profile_filename.
   if c, ok := ctx.Module().(*Module); ok && c.sanitize.isSanitizerEnabled(Hwasan) {
    flags.Local.CommonFlags = append(flags.Local.CommonFlags, clangCoverageHWASanFlags...)
   }
  }
 }

 // Even if we don't have coverage enabled, if any of our object files were compiled
 // with coverage, then we need to add --coverage to our ldflags.
 if !cov.linkCoverage {
  if ctx.staticLibrary() {
   // For static libraries, the only thing that changes our object files
   // are included whole static libraries, so check to see if any of
   // those have coverage enabled.
   ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) {
    if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok {
     if depTag.static() && depTag.wholeStatic {
      if info, ok := android.OtherModuleProvider(ctx, m, LinkableInfoProvider); ok {
       if info.LinkCoverage {
        cov.linkCoverage = true
       }
      }
     }
    }
   })
  } else {
   // For executables and shared libraries, we need to check all of
   // our static dependencies.
   ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) {
    if _, ok := android.OtherModuleProvider(ctx, m, StaticLibraryInfoProvider); ok {
     if info, ok := android.OtherModuleProvider(ctx, m, LinkableInfoProvider); ok {
      if info.LinkCoverage {
       cov.linkCoverage = true
      }
     }
    }
   })
  }
 }

 if cov.linkCoverage {
  if gcovCoverage {
   flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage")

   if ctx.Device() {
    coverage := ctx.GetDirectDepProxyWithTag(getGcovProfileLibraryName(ctx), CoverageDepTag)
    deps.WholeStaticLibs = append(deps.WholeStaticLibs, android.OutputFileForModule(ctx, coverage, ""))
    flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv")
   }
  } else if clangCoverage {
   flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrFlag)
   if EnableContinuousCoverage(ctx) {
    flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm=-runtime-counter-relocation")
   }

   if ctx.Device() {
    coverage := ctx.GetDirectDepProxyWithTag(getClangProfileLibraryName(ctx), CoverageDepTag)
    deps.WholeStaticLibs = append(deps.WholeStaticLibs, android.OutputFileForModule(ctx, coverage, ""))
    flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,open")
   }
  }
 }

 return flags, deps
}

func (cov *coverage) begin(ctx BaseModuleContext, binary bool, test bool) {
 if IsCoverageEnabled(ctx, binary, test) {
  cov.Properties = SetCoverageProperties(ctx, cov.Properties, ctx.nativeCoverage(), ctx.useSdk(), ctx.sdkVersion())
 }
}

func IsCoverageEnabled(ctx android.BaseModuleContext, binary bool, test bool) bool {
 if ctx.Host() {
  // Only allow coverage for host modules if they are explicitly marked as tests
  // or if they are libraries (which might be dependencies of tests).
  // Build tools (binaries that are NOT tests) should be excluded.
  if binary && !test {
   return false
  }
  // Host coverage is only supported on Linux 64-bit binaries
  if !ctx.Os().Linux() {
   return false
  }
  if ctx.Arch().ArchType.Multilib == "lib32" {
   return false
  }
 }
 return true
}

func SetCoverageProperties(ctx android.BaseModuleContext, properties CoverageProperties, moduleTypeHasCoverage bool,
 useSdk bool, sdkVersion string) CoverageProperties {
 // Coverage is disabled globally
 if !ctx.DeviceConfig().NativeCoverageEnabled() {
  return properties
 }

 var needCoverageVariant bool
 var needCoverageBuild bool

 if moduleTypeHasCoverage {
  // Check if Native_coverage is set to false.  This property defaults to true.
  needCoverageVariant = BoolDefault(properties.Native_coverage, true)
  if useSdk && sdkVersion != "current" {
   // Native coverage is not supported for SDK versions < 23
   if fromApi, err := strconv.Atoi(sdkVersion); err == nil && fromApi < 23 {
    needCoverageVariant = false
   }
  }

  // Coverage is still untested with LFI
  if ctx.Target().LFI {
   needCoverageVariant = false
  }

  if needCoverageVariant {
   // Coverage variant is actually built with coverage if enabled for its module path
   needCoverageBuild = ctx.DeviceConfig().NativeCoverageEnabledForPath(ctx.ModuleDir())
  }
 }

 properties.NeedCoverageBuild = needCoverageBuild
 properties.NeedCoverageVariant = needCoverageVariant

 return properties
}

type IsNativeCoverageNeededContext interface {
 Config() android.Config
 DeviceConfig() android.DeviceConfig
 Device() bool
}

var _ IsNativeCoverageNeededContext = android.IncomingTransitionContext(nil)
var _ IsNativeCoverageNeededContext = android.BaseModuleContext(nil)
var _ IsNativeCoverageNeededContext = android.BottomUpMutatorContext(nil)

type UseCoverage interface {
 android.Module
 IsNativeCoverageNeeded(ctx IsNativeCoverageNeededContext) bool
}

// Coverage is an interface for non-CC modules to implement to be mutated for coverage
type Coverage interface {
 UseCoverage
 SetPreventInstall()
 HideFromMake()
 MarkAsCoverageVariant(bool)
 EnableCoverageIfNeeded()
}

type UseCoverageDeptag interface {
 IsNativeCoverageNeededDepTag(ctx IsNativeCoverageNeededContext) bool
}

type coverageTransitionMutator struct{}

func (c coverageTransitionMutator) split(ctx android.BaseModuleContext) []string {
 if c, ok := ctx.Module().(*Module); ok && c.coverage != nil {
  if c.coverage.Properties.NeedCoverageVariant {
   return []string{"", "cov"}
  }
 } else if cov, ok := ctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(ctx) {
  // APEX and Rust modules fall here

  // 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
  // to an APEX via 'data' property.
  return []string{"", "cov"}
 } else if cov, ok := ctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(ctx) {
  // Module itself doesn't have to have "cov" variant, but it should use "cov" variants of
  // deps.
  return []string{"cov"}
 }

 return []string{""}
}

func (c coverageTransitionMutator) Split(ctx android.BaseModuleContext) []string {
 allSplits := c.split(ctx)
 if ctx.Config().GetBuildFlagBool("RELEASE_SOONG_COV_VARIANT_ON_DEMAND") {
  return allSplits[0:1]
 } else {
  return allSplits
 }
}

func (c coverageTransitionMutator) SplitOnDemand(ctx android.BaseModuleContext) []string {
 allSplits := c.split(ctx)
 if len(allSplits) <= 1 || !ctx.Config().GetBuildFlagBool("RELEASE_SOONG_COV_VARIANT_ON_DEMAND") {
  return nil
 } else {
  return allSplits[1:]
 }
}

func (c coverageTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
 return sourceVariation
}

func (c coverageTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
 if c, ok := ctx.Module().(*Module); ok && c.coverage != nil {
  if !c.coverage.Properties.NeedCoverageVariant {
   return ""
  }
 } else if cov, ok := ctx.Module().(Coverage); ok {
  if !cov.IsNativeCoverageNeeded(ctx) {
   return ""
  }
 } else if cov, ok := ctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(ctx) {
  // Module only has a "cov" variation, so all incoming variations should use "cov".
  return "cov"
 } else {
  return ""
 }

 // non-coverage variants have PreventInstall = true, so we need certain deptags that are
 // used for installation to use the coverage variant so that filesystem modules will package
 // them correctly.
 if x, ok := ctx.DepTag().(UseCoverageDeptag); (ok && x.IsNativeCoverageNeededDepTag(ctx)) || ctx.DepTag() == android.RequiredDepTag {
  return "cov"
 }

 return incomingVariation
}

func (c coverageTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
 if c, ok := ctx.Module().(*Module); ok && c.coverage != nil {
  if variation == "" && c.coverage.Properties.NeedCoverageVariant {
   // Setup the non-coverage version and set HideFromMake and
   // PreventInstall to true.
   c.coverage.Properties.CoverageEnabled = false
   c.coverage.Properties.IsCoverageVariant = false
   c.Properties.HideFromMake = true
   c.Properties.PreventInstall = true
  } else if variation == "cov" {
   // The coverage-enabled version inherits HideFromMake,
   // PreventInstall from the original module.
   c.coverage.Properties.CoverageEnabled = c.coverage.Properties.NeedCoverageBuild
   c.coverage.Properties.IsCoverageVariant = true
  }
 } else if cov, ok := ctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(ctx) {
  // APEX and Rust modules fall here

  // 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
  // to an APEX via 'data' property.
  if variation == "" {
   cov.MarkAsCoverageVariant(false)
   cov.SetPreventInstall()
   cov.HideFromMake()
  } else if variation == "cov" {
   cov.MarkAsCoverageVariant(true)
   cov.EnableCoverageIfNeeded()
  }
 } else if cov, ok := ctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(ctx) {
  // Module itself doesn't have to have "cov" variant, but it should use "cov" variants of
  // deps.
 }
}

func ParseSymbolFileForAPICoverage(ctx android.ModuleContext, symbolFile string) android.ModuleOutPath {
 apiLevelsJson := android.GetApiLevelsJson(ctx)
 symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
 outputFile := ctx.Module().(LinkableInterface).BaseModuleName() + ".xml"
 parsedApiCoveragePath := android.PathForModuleOut(ctx, outputFile)
 rule := android.NewRuleBuilder(pctx, ctx).SandboxDisabled()
 rule.Command().
  BuiltTool("ndk_api_coverage_parser").
  Input(symbolFilePath).
  Output(parsedApiCoveragePath).
  Implicit(apiLevelsJson).
  FlagWithArg("--api-map ", apiLevelsJson.String())
 rule.Build("native_library_api_list", "Generate native API list based on symbol files for coverage measurement")
 return parsedApiCoveragePath
}

[Dauer der Verarbeitung: 0.24 Sekunden, vorverarbeitet 2026-06-28]