Skip to content

Commit f02bcf8

Browse files
krisukoxcopybara-github
authored andcommitted
Fix identical gcov json file name problem
**The problem:** Bazel moves all `.gcov.json.gz` files to one directory. If in a test target, two source files have identical names, then the second `.gcov.json.gz` overwrites the first one. **The solution:** I added `gcno_path` to the move destination in order to distinguish multiple `.gcov.json.gz` with the same name. **Testing:** In the `test_cc_test_coverage_gcov` test case I added the `different/a.cc` source file, so currently we have the following source tree: ``` coverage_srcs/a.h coverage_srcs/a.cc coverage_srcs/b.h coverage_srcs/t.cc coverage_srcs/different/a.h coverage_srcs/different/a.cc ``` gcda and gcno files are created next to the source files. The final `gcov.json` files are placed in the corresponding paths: ``` $COVERAGE_DIR_VAR/coverage_srcs/*a.gcov.json.gz $COVERAGE_DIR_VAR/coverage_srcs/*t.gcov.json.gz $COVERAGE_DIR_VAR/coverage_srcs/different/*a.gcov.json.gz ``` Closes bazelbuild#16527. PiperOrigin-RevId: 483911427 Change-Id: I1608407e4b7264fb5fd436997bdc344344932b97
1 parent 8ef60d0 commit f02bcf8

File tree

2 files changed

+89
-52
lines changed

2 files changed

+89
-52
lines changed

src/test/shell/bazel/bazel_cc_code_coverage_test.sh

+88-51
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ function set_up() {
7070

7171
# Create the CC sources.
7272
mkdir -p "$ROOT_VAR/coverage_srcs/"
73+
mkdir -p "$ROOT_VAR/coverage_srcs/different"
7374
cat << EOF > "$ROOT_VAR/coverage_srcs/a.h"
7475
int a(bool what);
7576
EOF
@@ -85,6 +86,20 @@ int a(bool what) {
8586
return b(-1);
8687
}
8788
}
89+
EOF
90+
91+
cat << EOF > "$ROOT_VAR/coverage_srcs/different/a.h"
92+
int different_a(bool what);
93+
EOF
94+
95+
cat << EOF > "$ROOT_VAR/coverage_srcs/different/a.cc"
96+
int different_a(bool what) {
97+
if (what) {
98+
return 1;
99+
} else {
100+
return 2;
101+
}
102+
}
88103
EOF
89104

90105
cat << EOF > "$ROOT_VAR/coverage_srcs/b.h"
@@ -100,37 +115,24 @@ EOF
100115
cat << EOF > "$ROOT_VAR/coverage_srcs/t.cc"
101116
#include <stdio.h>
102117
#include "a.h"
118+
#include "different/a.h"
103119
104120
int main(void) {
105121
a(true);
122+
different_a(false);
106123
}
107124
EOF
108125

109126
generate_and_execute_instrumented_binary coverage_srcs/test \
110-
coverage_srcs/a.h coverage_srcs/a.cc \
111-
coverage_srcs/b.h \
112-
coverage_srcs/t.cc
113-
114-
# Prior to version 11, g++ generates the notes files in the current directory
115-
# instead of next to the object file despite the documentation indicating otherwise:
116-
# https://gcc.gnu.org/onlinedocs/gcc/Gcov-Data-Files.html#Gcov-Data-Files
117-
# This is fixed in g++ 11 so we have to handle both cases.
118-
119-
local not_found=0
120-
ls coverage_srcs/*a.gcno > /dev/null 2>&1 || not_found=$?
121-
if [[ $not_found -ne 0 ]]; then
122-
agcno=$(ls *a.gcno)
123-
tgcno=$(ls *t.gcno)
124-
agcda=$(ls *a.gcda)
125-
tgcda=$(ls *t.gcda)
126-
mv $agcno coverage_srcs/$agcno
127-
mv $tgcno coverage_srcs/$tgcno
128-
mv $agcda coverage_srcs/$agcda
129-
mv $tgcda coverage_srcs/$tgcda
130-
fi
127+
coverage_srcs/a.cc coverage_srcs/a.o \
128+
coverage_srcs/different/a.cc coverage_srcs/different/a.o \
129+
coverage_srcs/t.cc coverage_srcs/t.o
130+
131131
agcno=$(ls coverage_srcs/*a.gcno)
132+
dagcno=$(ls coverage_srcs/different/*a.gcno)
132133
tgcno=$(ls coverage_srcs/*t.gcno)
133134
agcda=$(ls coverage_srcs/*a.gcda)
135+
dagcda=$(ls coverage_srcs/different/*a.gcda)
134136
tgcda=$(ls coverage_srcs/*t.gcda)
135137
# Even though gcov expects the gcda files to be next to the gcno files,
136138
# during Bazel execution this will not be the case. collect_cc_coverage.sh
@@ -140,32 +142,41 @@ EOF
140142
# https://github.com/bazelbuild/bazel/issues/16229
141143
mv $agcda "$COVERAGE_DIR_VAR/$agcda"
142144
mv $tgcda "$COVERAGE_DIR_VAR/$tgcda"
145+
mkdir "$COVERAGE_DIR_VAR/$(dirname ${dagcda})"
146+
mv $dagcda "$COVERAGE_DIR_VAR/$dagcda"
143147

144148
# All generated .gcno files need to be in the manifest otherwise
145149
# the coverage report will be incomplete.
146150
echo "$tgcno" >> "$COVERAGE_MANIFEST_VAR"
147151
echo "$agcno" >> "$COVERAGE_MANIFEST_VAR"
152+
echo "$dagcno" >> "$COVERAGE_MANIFEST_VAR"
148153
}
149154

150155
# Generates and executes an instrumented binary:
151156
#
152-
# Reads the list of arguments provided by the caller (using $@) and uses them
153-
# to produce an instrumented binary using g++. This step also generates
154-
# the notes (.gcno) files.
157+
# Reads the list of source files along with object files paths. Uses them
158+
# to produce object files and link them to an instrumented binary using g++.
159+
# This step also generates the notes (.gcno) files.
155160
#
156161
# Executes the instrumented binary. This step also generates the
157162
# profile data (.gcda) files.
163+
#
164+
# - [(source_file, object_file),...] - source files and object file paths
158165
# - path_to_binary destination of the binary produced by g++
159166
function generate_and_execute_instrumented_binary() {
160167
local path_to_binary="${1}"; shift
161-
g++ -coverage \
162-
"$@" -o "$path_to_binary" \
163-
|| fail "Couldn't produce the instrumented binary for $@ \
164-
with path_to_binary $path_to_binary"
165-
166-
# Execute the instrumented binary and generates the profile data (.gcda)
167-
# file.
168-
# The profile data file is placed in $gcda_directory.
168+
local src_file=""
169+
local obj_file=""
170+
local obj_files=""
171+
while [[ $# -ge 2 ]]; do
172+
src_file=$1; shift
173+
obj_file=$1; shift
174+
obj_files="${obj_files} $obj_file"
175+
g++ -coverage -fprofile-arcs -ftest-coverage -lgcov -c \
176+
"$src_file" -o "$obj_file"
177+
done
178+
179+
g++ -coverage -fprofile-arcs -ftest-coverage -lgcov -o "$path_to_binary" $obj_files
169180
"$path_to_binary" || fail "Couldn't execute the instrumented binary \
170181
$path_to_binary"
171182
}
@@ -223,11 +234,12 @@ function assert_gcov_coverage_srcs_t_cc() {
223234
local output_file="${1}"; shift
224235

225236
# The expected coverage result for coverage_srcs/t.cc in gcov format.
226-
local expected_gcov_result_t_cc="file:coverage_srcs/t.cc
227-
function:4,1,main
228-
lcount:4,1
237+
local expected_gcov_result_t_cc="coverage_srcs/t.cc
238+
function:5,1,main
229239
lcount:5,1
230-
lcount:6,1"
240+
lcount:6,1
241+
lcount:7,1
242+
lcount:8,1"
231243
assert_coverage_entry_in_file "$expected_gcov_result_t_cc" "$output_file"
232244
}
233245

@@ -244,6 +256,19 @@ lcount:5,0"
244256
assert_coverage_entry_in_file "$expected_gcov_result" "$output_file"
245257
}
246258

259+
function assert_gcov_coverage_srcs_d_a_cc() {
260+
local output_file="${1}"; shift
261+
262+
# The expected coverage result for coverage_srcs/different/a.cc in gcov format.
263+
local expected_gcov_result_d_a_cc="file:coverage_srcs/different/a.cc
264+
function:1,1,_Z11different_ab
265+
lcount:1,1
266+
lcount:2,1
267+
lcount:3,0
268+
lcount:5,1"
269+
assert_coverage_entry_in_file "$expected_gcov_result_d_a_cc" "$output_file"
270+
}
271+
247272
function assert_gcov_coverage_srcs_a_cc_json() {
248273
local output_file="${1}"; shift
249274

@@ -265,7 +290,7 @@ function assert_gcov_coverage_srcs_t_cc_json() {
265290

266291
# The expected coverage result for coverage_srcs/t.cc in gcov format.
267292
cat > expected_gcov_result_t_cc <<EOF
268-
{"lines": [{"branches": [], "count": 1, "line_number": 4, "unexecuted_block": false, "function_name": "main"}, {"branches": [], "count": 1, "line_number": 5, "unexecuted_block": false, "function_name": "main"}, {"branches": [], "count": 1, "line_number": 6, "unexecuted_block": false, "function_name": "main"}], "functions": [{"blocks": 3, "end_column": 1, "start_line": 4, "name": "main", "blocks_executed": 3, "execution_count": 1, "demangled_name": "main", "start_column": 5, "end_line": 6}], "file": "coverage_srcs/t.cc"}
293+
{"lines": [{"branches": [], "count": 1, "line_number": 5, "unexecuted_block": false, "function_name": "main"}, {"branches": [], "count": 1, "line_number": 6, "unexecuted_block": false, "function_name": "main"}, {"branches": [], "count": 1, "line_number": 7, "unexecuted_block": false, "function_name": "main"}, {"branches": [], "count": 1, "line_number": 8, "unexecuted_block": false, "function_name": "main"}], "functions": [{"blocks": 4, "end_column": 1, "start_line": 5, "name": "main", "blocks_executed": 4, "execution_count": 1, "demangled_name": "main", "start_column": 5, "end_line": 8}], "file": "coverage_srcs/t.cc"}
269294
EOF
270295
local expected_gcov_result_t_cc=$(cat expected_gcov_result_t_cc | tr -d '\n')
271296
assert_coverage_entry_in_file "$expected_gcov_result_t_cc" "$output_file"
@@ -274,14 +299,24 @@ EOF
274299
function assert_gcov_coverage_srcs_b_h_json() {
275300
local output_file="${1}"; shift
276301

277-
# The expected coverage result for coverage_srcs/t.cc in gcov format.
302+
# The expected coverage result for coverage_srcs/b.h in gcov format.
278303
cat > expected_gcov_result_b_h <<EOF
279304
{"lines": [{"branches": [], "count": 1, "line_number": 1, "unexecuted_block": false, "function_name": "_Z1bi"}, {"branches": [], "count": 1, "line_number": 2, "unexecuted_block": false, "function_name": "_Z1bi"}, {"branches": [], "count": 1, "line_number": 3, "unexecuted_block": false, "function_name": "_Z1bi"}, {"branches": [], "count": 0, "line_number": 5, "unexecuted_block": true, "function_name": "_Z1bi"}], "functions": [{"blocks": 4, "end_column": 1, "start_line": 1, "name": "_Z1bi", "blocks_executed": 3, "execution_count": 1, "demangled_name": "b(int)", "start_column": 5, "end_line": 7}], "file": "coverage_srcs/b.h"}
280305
EOF
281306
local expected_gcov_result_b_h=$(cat expected_gcov_result_b_h | tr -d '\n')
282307
assert_coverage_entry_in_file "$expected_gcov_result_b_h" "$output_file"
283308
}
284309

310+
function assert_gcov_coverage_srcs_d_a_cc_json() {
311+
local output_file="${1}"; shift
312+
313+
# The expected coverage result for coverage_srcs/different/a.cc in gcov format.
314+
cat > expected_gcov_result_d_a_cc <<EOF
315+
{"lines": [{"branches": [], "count": 1, "line_number": 1, "unexecuted_block": false, "function_name": "_Z11different_ab"}, {"branches": [], "count": 1, "line_number": 2, "unexecuted_block": false, "function_name": "_Z11different_ab"}, {"branches": [], "count": 0, "line_number": 3, "unexecuted_block": true, "function_name": "_Z11different_ab"}, {"branches": [], "count": 1, "line_number": 5, "unexecuted_block": false, "function_name": "_Z11different_ab"}], "functions": [{"blocks": 4, "end_column": 1, "start_line": 1, "name": "_Z11different_ab", "blocks_executed": 3, "execution_count": 1, "demangled_name": "different_a(bool)", "start_column": 5, "end_line": 7}], "file": "coverage_srcs/different/a.cc"}
316+
EOF
317+
local expected_gcov_result_d_a_cc=$(cat expected_gcov_result_d_a_cc | tr -d '\n')
318+
assert_coverage_entry_in_file "$expected_gcov_result_d_a_cc" "$output_file"
319+
}
285320

286321
function test_cc_test_coverage_gcov() {
287322
local -r gcov_location=$(which gcov)
@@ -303,9 +338,6 @@ function test_cc_test_coverage_gcov() {
303338
# Location of the output file of the C++ coverage script when gcov is used.
304339
local output_file="$COVERAGE_DIR_VAR/_cc_coverage.gcov"
305340

306-
# Location of the output file of the C++ coverage script when gcov is used.
307-
local output_file="$COVERAGE_DIR_VAR/_cc_coverage.gcov"
308-
309341
# If the file _cc_coverge.gcov does not exist, it means we are using gcc 9
310342
# or higher which uses json.gz files as intermediate format. We will keep
311343
# testing gcc 7 and 8 until most users have migrated.
@@ -319,35 +351,40 @@ function test_cc_test_coverage_gcov() {
319351
assert_gcov_coverage_srcs_a_cc "$output_file"
320352
assert_gcov_coverage_srcs_t_cc "$output_file"
321353
assert_gcov_coverage_srcs_b_h "$output_file"
354+
assert_gcov_coverage_srcs_d_a_cc "$output_file"
322355

323356
# This assertion is needed to make sure no other source files are included
324357
# in the output file.
325358
local nr_lines="$(wc -l < "$output_file")"
326-
[[ "$nr_lines" == 17 ]] || \
359+
[[ "$nr_lines" == 24 ]] || \
327360
fail "Number of lines in C++ gcov coverage output file is "\
328-
"$nr_lines and different than 17"
361+
"$nr_lines and different than 24"
329362
else
363+
330364
# There may or may not be "gcda" in the extension.
331365
local not_found=0
332-
ls $COVERAGE_DIR_VAR/*.gcda.gcov.json.gz > /dev/null 2>&1 || not_found=$?
366+
ls $COVERAGE_DIR_VAR/coverage_srcs/*.gcda.gcov.json.gz > /dev/null 2>&1 || not_found=$?
333367
if [[ $not_found -ne 0 ]]; then
334-
agcda=$(ls $COVERAGE_DIR_VAR/*a.gcov.json.gz)
335-
tgcda=$(ls $COVERAGE_DIR_VAR/*t.gcov.json.gz)
368+
agcda=$(ls $COVERAGE_DIR_VAR/coverage_srcs/*a.gcov.json.gz)
369+
tgcda=$(ls $COVERAGE_DIR_VAR/coverage_srcs/*t.gcov.json.gz)
370+
dagcda=$(ls $COVERAGE_DIR_VAR/coverage_srcs/different/*a.gcov.json.gz)
336371
else
337-
agcda=$(ls $COVERAGE_DIR_VAR/*a.gcda.gcov.json.gz)
338-
tgcda=$(ls $COVERAGE_DIR_VAR/*t.gcda.gcov.json.gz)
372+
agcda=$(ls $COVERAGE_DIR_VAR/coverage_srcs/*a.gcda.gcov.json.gz)
373+
tgcda=$(ls $COVERAGE_DIR_VAR/coverage_srcs/*t.gcda.gcov.json.gz)
374+
dagcda=$(ls $COVERAGE_DIR_VAR/coverage_srcs/different/*a.gcda.gcov.json.gz)
339375
fi
340376
output_file_json="output_file.json"
341-
zcat $agcda $tgcda > $output_file_json
377+
zcat $agcda $tgcda $dagcda > $output_file_json
342378

343379
assert_gcov_coverage_srcs_a_cc_json "$output_file_json"
344380
assert_gcov_coverage_srcs_t_cc_json "$output_file_json"
345381
assert_gcov_coverage_srcs_b_h_json "$output_file_json"
382+
assert_gcov_coverage_srcs_d_a_cc_json "$output_file_json"
346383

347384
local nr_files="$(grep -o -i "\"file\":" "$output_file_json" | wc -l)"
348-
[[ "$nr_files" == 3 ]] || \
385+
[[ "$nr_files" == 4 ]] || \
349386
fail "Number of files in C++ gcov coverage output file is "\
350-
"$nr_files and different than 3"
387+
"$nr_files and different than 4"
351388
fi
352389
}
353390

tools/test/collect_cc_coverage.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ function gcov_coverage() {
163163
# gcov 9 or higher use a JSON based format for their coverage reports.
164164
# The output is generated into multiple files: "$(basename ${gcda}).gcov.json.gz"
165165
# Concatenating JSON documents does not yield a valid document, so they are moved individually
166-
mv -- *.gcov.json.gz "$(dirname "$output_file")"
166+
mv -- *.gcov.json.gz "$(dirname "$output_file")/$(dirname ${gcno_path})"
167167
else
168168
# Append all .gcov files in the current directory to the output file.
169169
cat -- *.gcov >> "$output_file"

0 commit comments

Comments
 (0)