• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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