1// Copyright 2017 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package cc 16 17import ( 18 "strconv" 19 20 "android/soong/android" 21) 22 23type CoverageProperties struct { 24 Native_coverage *bool 25 26 NeedCoverageVariant bool `blueprint:"mutated"` 27 NeedCoverageBuild bool `blueprint:"mutated"` 28 29 CoverageEnabled bool `blueprint:"mutated"` 30 IsCoverageVariant bool `blueprint:"mutated"` 31} 32 33type coverage struct { 34 Properties CoverageProperties 35 36 // Whether binaries containing this module need --coverage added to their ldflags 37 linkCoverage bool 38} 39 40func (cov *coverage) props() []interface{} { 41 return []interface{}{&cov.Properties} 42} 43 44func (cov *coverage) deps(ctx BaseModuleContext, deps Deps) Deps { 45 if cov.Properties.NeedCoverageBuild { 46 // Link libprofile-extras/libprofile-extras_ndk when coverage 47 // variant is required. This is a no-op unless coverage is 48 // actually enabled during linking, when 49 // '-uinit_profile_extras' is added (in flags()) to force the 50 // setup code in libprofile-extras be linked into the 51 // binary/library. 52 // 53 // We cannot narrow it further to only the 'cov' variant since 54 // the mutator hasn't run (and we don't have the 'cov' variant 55 // yet). 56 if !ctx.useSdk() { 57 deps.LateStaticLibs = append(deps.LateStaticLibs, "libprofile-extras") 58 } else { 59 deps.LateStaticLibs = append(deps.LateStaticLibs, "libprofile-extras_ndk") 60 } 61 } 62 return deps 63} 64 65func (cov *coverage) flags(ctx ModuleContext, flags Flags) Flags { 66 if !ctx.DeviceConfig().NativeCoverageEnabled() { 67 return flags 68 } 69 70 if cov.Properties.CoverageEnabled { 71 flags.Coverage = true 72 flags.GlobalFlags = append(flags.GlobalFlags, "--coverage", "-O0") 73 cov.linkCoverage = true 74 75 // Override -Wframe-larger-than and non-default optimization 76 // flags that the module may use. 77 flags.CFlags = append(flags.CFlags, "-Wno-frame-larger-than=", "-O0") 78 } 79 80 // Even if we don't have coverage enabled, if any of our object files were compiled 81 // with coverage, then we need to add --coverage to our ldflags. 82 if !cov.linkCoverage { 83 if ctx.static() && !ctx.staticBinary() { 84 // For static libraries, the only thing that changes our object files 85 // are included whole static libraries, so check to see if any of 86 // those have coverage enabled. 87 ctx.VisitDirectDepsWithTag(wholeStaticDepTag, func(m android.Module) { 88 if cc, ok := m.(*Module); ok && cc.coverage != nil { 89 if cc.coverage.linkCoverage { 90 cov.linkCoverage = true 91 } 92 } 93 }) 94 } else { 95 // For executables and shared libraries, we need to check all of 96 // our static dependencies. 97 ctx.VisitDirectDeps(func(m android.Module) { 98 cc, ok := m.(*Module) 99 if !ok || cc.coverage == nil { 100 return 101 } 102 103 if static, ok := cc.linker.(libraryInterface); !ok || !static.static() { 104 return 105 } 106 107 if cc.coverage.linkCoverage { 108 cov.linkCoverage = true 109 } 110 }) 111 } 112 } 113 114 if cov.linkCoverage { 115 flags.LdFlags = append(flags.LdFlags, "--coverage") 116 117 // Force linking of constructor/setup code in libprofile-extras 118 flags.LdFlags = append(flags.LdFlags, "-uinit_profile_extras") 119 } 120 121 return flags 122} 123 124func (cov *coverage) begin(ctx BaseModuleContext) { 125 // Coverage is disabled globally 126 if !ctx.DeviceConfig().NativeCoverageEnabled() { 127 return 128 } 129 130 var needCoverageVariant bool 131 var needCoverageBuild bool 132 133 if ctx.Host() { 134 // TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a 135 // Just turn off for now. 136 } else if !ctx.nativeCoverage() { 137 // Native coverage is not supported for this module type. 138 } else { 139 // Check if Native_coverage is set to false. This property defaults to true. 140 needCoverageVariant = BoolDefault(cov.Properties.Native_coverage, true) 141 142 if sdk_version := ctx.sdkVersion(); ctx.useSdk() && sdk_version != "current" { 143 // Native coverage is not supported for SDK versions < 23 144 if fromApi, err := strconv.Atoi(sdk_version); err == nil && fromApi < 23 { 145 needCoverageVariant = false 146 } 147 } 148 149 if needCoverageVariant { 150 // Coverage variant is actually built with coverage if enabled for its module path 151 needCoverageBuild = ctx.DeviceConfig().CoverageEnabledForPath(ctx.ModuleDir()) 152 } 153 } 154 155 cov.Properties.NeedCoverageBuild = needCoverageBuild 156 cov.Properties.NeedCoverageVariant = needCoverageVariant 157} 158 159func coverageMutator(mctx android.BottomUpMutatorContext) { 160 if c, ok := mctx.Module().(*Module); ok && c.coverage != nil { 161 needCoverageVariant := c.coverage.Properties.NeedCoverageVariant 162 needCoverageBuild := c.coverage.Properties.NeedCoverageBuild 163 if needCoverageVariant { 164 m := mctx.CreateVariations("", "cov") 165 166 // Setup the non-coverage version and set HideFromMake and 167 // PreventInstall to true. 168 m[0].(*Module).coverage.Properties.CoverageEnabled = false 169 m[0].(*Module).coverage.Properties.IsCoverageVariant = false 170 m[0].(*Module).Properties.HideFromMake = true 171 m[0].(*Module).Properties.PreventInstall = true 172 173 // The coverage-enabled version inherits HideFromMake, 174 // PreventInstall from the original module. 175 m[1].(*Module).coverage.Properties.CoverageEnabled = needCoverageBuild 176 m[1].(*Module).coverage.Properties.IsCoverageVariant = true 177 } 178 } 179} 180