1*61c4878aSAndroid Build Coastguard Worker# Copyright 2023 The Pigweed Authors 2*61c4878aSAndroid Build Coastguard Worker# 3*61c4878aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4*61c4878aSAndroid Build Coastguard Worker# use this file except in compliance with the License. You may obtain a copy of 5*61c4878aSAndroid Build Coastguard Worker# the License at 6*61c4878aSAndroid Build Coastguard Worker# 7*61c4878aSAndroid Build Coastguard Worker# https://www.apache.org/licenses/LICENSE-2.0 8*61c4878aSAndroid Build Coastguard Worker# 9*61c4878aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*61c4878aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11*61c4878aSAndroid Build Coastguard Worker# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12*61c4878aSAndroid Build Coastguard Worker# License for the specific language governing permissions and limitations under 13*61c4878aSAndroid Build Coastguard Worker# the License. 14*61c4878aSAndroid Build Coastguard Worker 15*61c4878aSAndroid Build Coastguard Workerimport("//build_overrides/pigweed.gni") 16*61c4878aSAndroid Build Coastguard Workerimport("//build_overrides/pigweed_environment.gni") 17*61c4878aSAndroid Build Coastguard Worker 18*61c4878aSAndroid Build Coastguard Workerimport("$dir_pw_build/python_action.gni") 19*61c4878aSAndroid Build Coastguard Workerimport("$dir_pw_toolchain/host_clang/toolchains.gni") 20*61c4878aSAndroid Build Coastguard Worker 21*61c4878aSAndroid Build Coastguard Worker# Expands to code coverage targets that can be used as dependencies to generate 22*61c4878aSAndroid Build Coastguard Worker# coverage reports at build time. 23*61c4878aSAndroid Build Coastguard Worker# 24*61c4878aSAndroid Build Coastguard Worker# Arguments: 25*61c4878aSAndroid Build Coastguard Worker# - enable_if (optional): Conditionally activates coverage report generation 26*61c4878aSAndroid Build Coastguard Worker# when set to a boolean expression that evaluates to true. 27*61c4878aSAndroid Build Coastguard Worker# - failure_mode (optional/unstable): Specify the failure mode for llvm-profdata 28*61c4878aSAndroid Build Coastguard Worker# (used to merge inidividual profraw files from pw_test runs). Available 29*61c4878aSAndroid Build Coastguard Worker# options are "any" (default) or "all". This should be considered an 30*61c4878aSAndroid Build Coastguard Worker# unstable/deprecated argument that should only be used as a last resort to 31*61c4878aSAndroid Build Coastguard Worker# get a build working again. Using failure_mode = "all" usually indicates that 32*61c4878aSAndroid Build Coastguard Worker# there are underlying problems in the build or test infrastructure that 33*61c4878aSAndroid Build Coastguard Worker# should be independently resolved. Please reach out to the Pigweed team for 34*61c4878aSAndroid Build Coastguard Worker# assistance. 35*61c4878aSAndroid Build Coastguard Worker# - Coverage Settings 36*61c4878aSAndroid Build Coastguard Worker# - filter_paths (optional): List of file paths (using GN path helpers like 37*61c4878aSAndroid Build Coastguard Worker# `//` is supported). These will be translated into absolute paths before 38*61c4878aSAndroid Build Coastguard Worker# being used. These filter source files so that the coverage report *ONLY* 39*61c4878aSAndroid Build Coastguard Worker# includes files that match one of these paths. These cannot be regular 40*61c4878aSAndroid Build Coastguard Worker# expressions, but can be concrete file or folder paths. Folder paths will 41*61c4878aSAndroid Build Coastguard Worker# allow all files in that directory or any recursive child directory. 42*61c4878aSAndroid Build Coastguard Worker# - ignore_filename_patterns (optional): List of file path regular expressions 43*61c4878aSAndroid Build Coastguard Worker# to ignore when generating the coverage report. 44*61c4878aSAndroid Build Coastguard Worker# - pw_test Depedencies (required): These control which test binaries are used 45*61c4878aSAndroid Build Coastguard Worker# to collect usage data for the coverage report. The following can basically 46*61c4878aSAndroid Build Coastguard Worker# be used interchangeably with no actual difference in the template expansion. 47*61c4878aSAndroid Build Coastguard Worker# Only one of these is required to be provided. 48*61c4878aSAndroid Build Coastguard Worker# - tests: A list of pw_test targets. 49*61c4878aSAndroid Build Coastguard Worker# - group_deps: A list of pw_test_group targets. 50*61c4878aSAndroid Build Coastguard Worker# 51*61c4878aSAndroid Build Coastguard Worker# Expands To: 52*61c4878aSAndroid Build Coastguard Worker# pw_coverage_report follows the overall Pigweed pattern where targets exist 53*61c4878aSAndroid Build Coastguard Worker# for all build configurations, but are only configured to do meaningful work 54*61c4878aSAndroid Build Coastguard Worker# under the correct build configuration. In this vein, pw_coverage_report 55*61c4878aSAndroid Build Coastguard Worker# ensures that a coverage-enabled toolchain is being used and the provided 56*61c4878aSAndroid Build Coastguard Worker# enable_if evaluates to true (if provided). 57*61c4878aSAndroid Build Coastguard Worker# 58*61c4878aSAndroid Build Coastguard Worker# - If a coverage-enabled toolchain is being used and the provided enable_if 59*61c4878aSAndroid Build Coastguard Worker# evaluates to true (if provided): 60*61c4878aSAndroid Build Coastguard Worker# - <target_name>.text: Generates a text representation of the coverage 61*61c4878aSAndroid Build Coastguard Worker# report. This is the output of 62*61c4878aSAndroid Build Coastguard Worker# `llvm-cov show --format text`. 63*61c4878aSAndroid Build Coastguard Worker# - <target_name>.html: Generates an HTML representation of the coverage 64*61c4878aSAndroid Build Coastguard Worker# report. This is the output of 65*61c4878aSAndroid Build Coastguard Worker# `llvm-cov show --format html`. 66*61c4878aSAndroid Build Coastguard Worker# - <target_name>.lcov: Generates an LCOV representation of the coverage 67*61c4878aSAndroid Build Coastguard Worker# report. This is the output of 68*61c4878aSAndroid Build Coastguard Worker# `llvm-cov export --format lcov`. 69*61c4878aSAndroid Build Coastguard Worker# - <target_name>.json: Generates a JSON representation of the coverage 70*61c4878aSAndroid Build Coastguard Worker# report. This is the output of 71*61c4878aSAndroid Build Coastguard Worker# `llvm-cov export --format text`. 72*61c4878aSAndroid Build Coastguard Worker# 73*61c4878aSAndroid Build Coastguard Worker# - <target_name>: A group that takes dependencies on <target_name>.text, 74*61c4878aSAndroid Build Coastguard Worker# <target_name>.html, <target_name>.lcov, and 75*61c4878aSAndroid Build Coastguard Worker# <target_name>.json. This can be used to force generation of 76*61c4878aSAndroid Build Coastguard Worker# all coverage artifacts without manually depending on each 77*61c4878aSAndroid Build Coastguard Worker# target. 78*61c4878aSAndroid Build Coastguard Worker# 79*61c4878aSAndroid Build Coastguard Worker# - The other targets this expands to should be considered private and not 80*61c4878aSAndroid Build Coastguard Worker# used as dependencies. 81*61c4878aSAndroid Build Coastguard Worker# - If a coverage-enabled toolchain is not being used or the provided enable_if 82*61c4878aSAndroid Build Coastguard Worker# evaluates to false (if provided). 83*61c4878aSAndroid Build Coastguard Worker# - All of the above target names, but they are empty groups. 84*61c4878aSAndroid Build Coastguard Workertemplate("pw_coverage_report") { 85*61c4878aSAndroid Build Coastguard Worker assert(defined(invoker.tests) || defined(invoker.group_deps), 86*61c4878aSAndroid Build Coastguard Worker "One of `tests` or `group_deps` must be provided.") 87*61c4878aSAndroid Build Coastguard Worker assert(!defined(invoker.failure_mode) || 88*61c4878aSAndroid Build Coastguard Worker (invoker.failure_mode == "any" || invoker.failure_mode == "all"), 89*61c4878aSAndroid Build Coastguard Worker "failure_mode only supports \"any\" or \"all\".") 90*61c4878aSAndroid Build Coastguard Worker 91*61c4878aSAndroid Build Coastguard Worker _report_name = target_name 92*61c4878aSAndroid Build Coastguard Worker _format_types = [ 93*61c4878aSAndroid Build Coastguard Worker "text", 94*61c4878aSAndroid Build Coastguard Worker "html", 95*61c4878aSAndroid Build Coastguard Worker "lcov", 96*61c4878aSAndroid Build Coastguard Worker "json", 97*61c4878aSAndroid Build Coastguard Worker ] 98*61c4878aSAndroid Build Coastguard Worker _should_enable = !defined(invoker.enable_if) || invoker.enable_if 99*61c4878aSAndroid Build Coastguard Worker 100*61c4878aSAndroid Build Coastguard Worker # These two Pigweed build arguments are required to be in these states to 101*61c4878aSAndroid Build Coastguard Worker # ensure binaries are instrumented for coverage and profraw files are 102*61c4878aSAndroid Build Coastguard Worker # exported. 103*61c4878aSAndroid Build Coastguard Worker if (_should_enable && pw_toolchain_COVERAGE_ENABLED) { 104*61c4878aSAndroid Build Coastguard Worker _test_metadata = "$target_out_dir/$_report_name.test_metadata.json" 105*61c4878aSAndroid Build Coastguard Worker _profdata_file = "$target_out_dir/merged.profdata" 106*61c4878aSAndroid Build Coastguard Worker _arguments = { 107*61c4878aSAndroid Build Coastguard Worker filter_paths = [] 108*61c4878aSAndroid Build Coastguard Worker if (defined(invoker.filter_paths)) { 109*61c4878aSAndroid Build Coastguard Worker filter_paths += invoker.filter_paths 110*61c4878aSAndroid Build Coastguard Worker } 111*61c4878aSAndroid Build Coastguard Worker 112*61c4878aSAndroid Build Coastguard Worker ignore_filename_patterns = [] 113*61c4878aSAndroid Build Coastguard Worker if (defined(invoker.ignore_filename_patterns)) { 114*61c4878aSAndroid Build Coastguard Worker ignore_filename_patterns += invoker.ignore_filename_patterns 115*61c4878aSAndroid Build Coastguard Worker } 116*61c4878aSAndroid Build Coastguard Worker 117*61c4878aSAndroid Build Coastguard Worker # Merge any provided `tests` or `group_deps` to `deps` and `run_deps`. 118*61c4878aSAndroid Build Coastguard Worker # 119*61c4878aSAndroid Build Coastguard Worker # `deps` are used to generate the .test_metadata.json file. 120*61c4878aSAndroid Build Coastguard Worker # `run_deps` are used to block on the test execution to generate a profraw 121*61c4878aSAndroid Build Coastguard Worker # file. 122*61c4878aSAndroid Build Coastguard Worker deps = [] 123*61c4878aSAndroid Build Coastguard Worker run_deps = [] 124*61c4878aSAndroid Build Coastguard Worker test_or_group_deps = [] 125*61c4878aSAndroid Build Coastguard Worker if (defined(invoker.tests)) { 126*61c4878aSAndroid Build Coastguard Worker test_or_group_deps += invoker.tests 127*61c4878aSAndroid Build Coastguard Worker } 128*61c4878aSAndroid Build Coastguard Worker if (defined(invoker.group_deps)) { 129*61c4878aSAndroid Build Coastguard Worker test_or_group_deps += invoker.group_deps 130*61c4878aSAndroid Build Coastguard Worker } 131*61c4878aSAndroid Build Coastguard Worker foreach(dep, test_or_group_deps) { 132*61c4878aSAndroid Build Coastguard Worker deps += [ dep ] 133*61c4878aSAndroid Build Coastguard Worker 134*61c4878aSAndroid Build Coastguard Worker dep_target = get_label_info(dep, "label_no_toolchain") 135*61c4878aSAndroid Build Coastguard Worker dep_toolchain = get_label_info(dep, "toolchain") 136*61c4878aSAndroid Build Coastguard Worker run_deps += [ "$dep_target.run($dep_toolchain)" ] 137*61c4878aSAndroid Build Coastguard Worker } 138*61c4878aSAndroid Build Coastguard Worker } 139*61c4878aSAndroid Build Coastguard Worker 140*61c4878aSAndroid Build Coastguard Worker # Generate a list of all test binaries and their associated profraw files 141*61c4878aSAndroid Build Coastguard Worker # after executing we can use to generate the coverage report. 142*61c4878aSAndroid Build Coastguard Worker generated_file("_$_report_name.test_metadata") { 143*61c4878aSAndroid Build Coastguard Worker outputs = [ _test_metadata ] 144*61c4878aSAndroid Build Coastguard Worker data_keys = [ 145*61c4878aSAndroid Build Coastguard Worker "unit_tests", 146*61c4878aSAndroid Build Coastguard Worker "profraws", 147*61c4878aSAndroid Build Coastguard Worker ] 148*61c4878aSAndroid Build Coastguard Worker output_conversion = "json" 149*61c4878aSAndroid Build Coastguard Worker deps = _arguments.deps 150*61c4878aSAndroid Build Coastguard Worker } 151*61c4878aSAndroid Build Coastguard Worker 152*61c4878aSAndroid Build Coastguard Worker # Merge the generated profraws from instrumented binaries into a single 153*61c4878aSAndroid Build Coastguard Worker # profdata. 154*61c4878aSAndroid Build Coastguard Worker pw_python_action("_$_report_name.merge_profraws") { 155*61c4878aSAndroid Build Coastguard Worker _depfile_path = "$target_out_dir/$_report_name.merged_profraws.d" 156*61c4878aSAndroid Build Coastguard Worker 157*61c4878aSAndroid Build Coastguard Worker module = "pw_build.merge_profraws" 158*61c4878aSAndroid Build Coastguard Worker args = [ 159*61c4878aSAndroid Build Coastguard Worker "--llvm-profdata-path", 160*61c4878aSAndroid Build Coastguard Worker pw_toolchain_clang_tools.llvm_profdata, 161*61c4878aSAndroid Build Coastguard Worker "--test-metadata-path", 162*61c4878aSAndroid Build Coastguard Worker rebase_path(_test_metadata, root_build_dir), 163*61c4878aSAndroid Build Coastguard Worker "--profdata-path", 164*61c4878aSAndroid Build Coastguard Worker rebase_path(_profdata_file, root_build_dir), 165*61c4878aSAndroid Build Coastguard Worker "--depfile-path", 166*61c4878aSAndroid Build Coastguard Worker rebase_path(_depfile_path, root_build_dir), 167*61c4878aSAndroid Build Coastguard Worker ] 168*61c4878aSAndroid Build Coastguard Worker 169*61c4878aSAndroid Build Coastguard Worker # TODO: b/256651964 - We really want `--failure-mode any` always to guarantee 170*61c4878aSAndroid Build Coastguard Worker # we don't silently ignore any profraw report. However, there are downstream 171*61c4878aSAndroid Build Coastguard Worker # projects that currently break when using `--failure-mode any`. 172*61c4878aSAndroid Build Coastguard Worker # 173*61c4878aSAndroid Build Coastguard Worker # See the task for examples of what is currently going wrong. 174*61c4878aSAndroid Build Coastguard Worker # 175*61c4878aSAndroid Build Coastguard Worker # Invalid profraw files will be ignored so coverage reports might have a 176*61c4878aSAndroid Build Coastguard Worker # slight variance between runs depending on if something failed or not. 177*61c4878aSAndroid Build Coastguard Worker if (defined(invoker.failure_mode)) { 178*61c4878aSAndroid Build Coastguard Worker args += [ 179*61c4878aSAndroid Build Coastguard Worker "--failure-mode", 180*61c4878aSAndroid Build Coastguard Worker invoker.failure_mode, 181*61c4878aSAndroid Build Coastguard Worker ] 182*61c4878aSAndroid Build Coastguard Worker } 183*61c4878aSAndroid Build Coastguard Worker 184*61c4878aSAndroid Build Coastguard Worker inputs = [ _test_metadata ] 185*61c4878aSAndroid Build Coastguard Worker sources = [] 186*61c4878aSAndroid Build Coastguard Worker depfile = _depfile_path 187*61c4878aSAndroid Build Coastguard Worker 188*61c4878aSAndroid Build Coastguard Worker outputs = [ _profdata_file ] 189*61c4878aSAndroid Build Coastguard Worker 190*61c4878aSAndroid Build Coastguard Worker python_deps = [ "$dir_pw_build/py" ] 191*61c4878aSAndroid Build Coastguard Worker deps = _arguments.run_deps 192*61c4878aSAndroid Build Coastguard Worker public_deps = [ ":_$_report_name.test_metadata" ] 193*61c4878aSAndroid Build Coastguard Worker } 194*61c4878aSAndroid Build Coastguard Worker 195*61c4878aSAndroid Build Coastguard Worker foreach(format, _format_types) { 196*61c4878aSAndroid Build Coastguard Worker pw_python_action("$_report_name.$format") { 197*61c4878aSAndroid Build Coastguard Worker _depfile_path = "$target_out_dir/$_report_name.$format.d" 198*61c4878aSAndroid Build Coastguard Worker _output_dir = "$target_out_dir/$_report_name/$format/" 199*61c4878aSAndroid Build Coastguard Worker 200*61c4878aSAndroid Build Coastguard Worker module = "pw_build.generate_report" 201*61c4878aSAndroid Build Coastguard Worker args = [ 202*61c4878aSAndroid Build Coastguard Worker "--llvm-cov-path", 203*61c4878aSAndroid Build Coastguard Worker pw_toolchain_clang_tools.llvm_cov, 204*61c4878aSAndroid Build Coastguard Worker "--format", 205*61c4878aSAndroid Build Coastguard Worker format, 206*61c4878aSAndroid Build Coastguard Worker "--test-metadata-path", 207*61c4878aSAndroid Build Coastguard Worker rebase_path(_test_metadata, root_build_dir), 208*61c4878aSAndroid Build Coastguard Worker "--profdata-path", 209*61c4878aSAndroid Build Coastguard Worker rebase_path(_profdata_file, root_build_dir), 210*61c4878aSAndroid Build Coastguard Worker "--root-dir", 211*61c4878aSAndroid Build Coastguard Worker rebase_path("//", root_build_dir), 212*61c4878aSAndroid Build Coastguard Worker "--build-dir", 213*61c4878aSAndroid Build Coastguard Worker ".", 214*61c4878aSAndroid Build Coastguard Worker "--output-dir", 215*61c4878aSAndroid Build Coastguard Worker rebase_path(_output_dir, root_build_dir), 216*61c4878aSAndroid Build Coastguard Worker "--depfile-path", 217*61c4878aSAndroid Build Coastguard Worker rebase_path(_depfile_path, root_build_dir), 218*61c4878aSAndroid Build Coastguard Worker ] 219*61c4878aSAndroid Build Coastguard Worker foreach(filter_path, _arguments.filter_paths) { 220*61c4878aSAndroid Build Coastguard Worker args += [ 221*61c4878aSAndroid Build Coastguard Worker # We rebase to absolute paths here to resolve any "//" used in the 222*61c4878aSAndroid Build Coastguard Worker # filter_paths. 223*61c4878aSAndroid Build Coastguard Worker "--filter-path", 224*61c4878aSAndroid Build Coastguard Worker rebase_path(filter_path), 225*61c4878aSAndroid Build Coastguard Worker ] 226*61c4878aSAndroid Build Coastguard Worker } 227*61c4878aSAndroid Build Coastguard Worker foreach(ignore_filename_pattern, _arguments.ignore_filename_patterns) { 228*61c4878aSAndroid Build Coastguard Worker args += [ 229*61c4878aSAndroid Build Coastguard Worker "--ignore-filename-pattern", 230*61c4878aSAndroid Build Coastguard Worker ignore_filename_pattern, 231*61c4878aSAndroid Build Coastguard Worker ] 232*61c4878aSAndroid Build Coastguard Worker } 233*61c4878aSAndroid Build Coastguard Worker 234*61c4878aSAndroid Build Coastguard Worker inputs = [ 235*61c4878aSAndroid Build Coastguard Worker _test_metadata, 236*61c4878aSAndroid Build Coastguard Worker _profdata_file, 237*61c4878aSAndroid Build Coastguard Worker ] 238*61c4878aSAndroid Build Coastguard Worker sources = [] 239*61c4878aSAndroid Build Coastguard Worker depfile = _depfile_path 240*61c4878aSAndroid Build Coastguard Worker 241*61c4878aSAndroid Build Coastguard Worker outputs = [] 242*61c4878aSAndroid Build Coastguard Worker if (format == "text") { 243*61c4878aSAndroid Build Coastguard Worker outputs += [ "$_output_dir/index.txt" ] 244*61c4878aSAndroid Build Coastguard Worker } else if (format == "html") { 245*61c4878aSAndroid Build Coastguard Worker outputs += [ "$_output_dir/index.html" ] 246*61c4878aSAndroid Build Coastguard Worker } else if (format == "lcov") { 247*61c4878aSAndroid Build Coastguard Worker outputs += [ "$_output_dir/report.lcov" ] 248*61c4878aSAndroid Build Coastguard Worker } else if (format == "json") { 249*61c4878aSAndroid Build Coastguard Worker outputs += [ "$_output_dir/report.json" ] 250*61c4878aSAndroid Build Coastguard Worker } 251*61c4878aSAndroid Build Coastguard Worker 252*61c4878aSAndroid Build Coastguard Worker python_deps = [ "$dir_pw_build/py" ] 253*61c4878aSAndroid Build Coastguard Worker deps = [ ":_$_report_name.merge_profraws" ] 254*61c4878aSAndroid Build Coastguard Worker } 255*61c4878aSAndroid Build Coastguard Worker } 256*61c4878aSAndroid Build Coastguard Worker } else { 257*61c4878aSAndroid Build Coastguard Worker not_needed(invoker, "*") 258*61c4878aSAndroid Build Coastguard Worker foreach(format, _format_types) { 259*61c4878aSAndroid Build Coastguard Worker group("$_report_name.$format") { 260*61c4878aSAndroid Build Coastguard Worker } 261*61c4878aSAndroid Build Coastguard Worker } 262*61c4878aSAndroid Build Coastguard Worker } 263*61c4878aSAndroid Build Coastguard Worker 264*61c4878aSAndroid Build Coastguard Worker group("$_report_name") { 265*61c4878aSAndroid Build Coastguard Worker deps = [] 266*61c4878aSAndroid Build Coastguard Worker foreach(format, _format_types) { 267*61c4878aSAndroid Build Coastguard Worker deps += [ ":$_report_name.$format" ] 268*61c4878aSAndroid Build Coastguard Worker } 269*61c4878aSAndroid Build Coastguard Worker } 270*61c4878aSAndroid Build Coastguard Worker} 271