#2 Update to lcov 2.0
Merged 7 months ago by berrange. Opened 7 months ago by terjeros.
rpms/ terjeros/lcov rawhide  into  rawhide

@@ -1,895 +0,0 @@ 

- From ebfeb3e179e450c69c3532f98cd5ea1fbf6ccba7 Mon Sep 17 00:00:00 2001

- From: Peter Oberparleiter <oberpar@linux.ibm.com>

- Date: Fri, 24 May 2019 16:56:52 +0200

- Subject: [PATCH 1/2] geninfo: Add intermediate text format support

- 

- This change adds support for parsing the output of gcov's intermediate

- text file format as implemented by GCC versions 5 to 8.  The use of the

- gcov intermediate format should increase processing speed. It also

- provides branch coverage data when using the --initial command line

- option.

- 

- Users can control whether geninfo uses the intermediate format via the

- geninfo_intermediate configuration file option. Valid values are:

- 

-      0: Use normal text format

-      1: Use intermediate format

-   auto: Use intermediate format if available. This is the default.

- 

- Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>

- ---

-  bin/geninfo  | 567 ++++++++++++++++++++++++++++++++++++++++++++-------

-  lcovrc       |   3 +

-  man/lcovrc.5 |  24 +++

-  3 files changed, 521 insertions(+), 73 deletions(-)

- 

- diff --git a/bin/geninfo b/bin/geninfo

- index 5a8b8b5..5453356 100755

- --- a/bin/geninfo

- +++ b/bin/geninfo

- @@ -54,6 +54,8 @@ use warnings;

-  use File::Basename; 

-  use File::Spec::Functions qw /abs2rel catdir file_name_is_absolute splitdir

-  			      splitpath catpath/;

- +use File::Temp qw(tempfile tempdir);

- +use File::Copy qw(copy);

-  use Getopt::Long;

-  use Digest::MD5 qw(md5_base64);

-  use Cwd qw/abs_path/;

- @@ -163,13 +165,13 @@ sub solve_relative_path($$);

-  sub read_gcov_header($);

-  sub read_gcov_file($);

-  sub info(@);

- +sub process_intermediate($$$);

-  sub map_llvm_version($);

-  sub version_to_str($);

-  sub get_gcov_version();

-  sub system_no_output($@);

-  sub read_config($);

-  sub apply_config($);

- -sub get_exclusion_data($);

-  sub apply_exclusion_data($$);

-  sub process_graphfile($$);

-  sub filter_fn_name($);

- @@ -264,6 +266,8 @@ our $gcno_split_crc;

-  our $func_coverage = 1;

-  our $br_coverage = 0;

-  our $rc_auto_base = 1;

- +our $rc_intermediate = "auto";

- +our $intermediate;

-  our $excl_line = "LCOV_EXCL_LINE";

-  our $excl_br_line = "LCOV_EXCL_BR_LINE";

-  

- @@ -331,6 +335,7 @@ if ($config || %opt_rc)

-  		"geninfo_compat"		=> \$opt_compat,

-  		"geninfo_adjust_src_path"	=> \$rc_adjust_src_path,

-  		"geninfo_auto_base"		=> \$rc_auto_base,

- +		"geninfo_intermediate"		=> \$rc_intermediate,

-  		"lcov_function_coverage"	=> \$func_coverage,

-  		"lcov_branch_coverage"		=> \$br_coverage,

-  		"lcov_excl_line"		=> \$excl_line,

- @@ -460,15 +465,38 @@ if (system_no_output(3, $gcov_tool, "--help") == -1)

-  }

-  

-  ($gcov_version, $gcov_version_string) = get_gcov_version();

- +$gcov_caps = get_gcov_capabilities();

- +

- +# Determine intermediate mode

- +if ($rc_intermediate eq "0") {

- +	$intermediate = 0;

- +} elsif ($rc_intermediate eq "1") {

- +	$intermediate = 1;

- +} elsif (lc($rc_intermediate) eq "auto") {

- +	# Use intermediate format if supported by gcov

- +	$intermediate = $gcov_caps->{'intermediate-format'} ? 1 : 0;

- +} else {

- +	die("ERROR: invalid value for geninfo_intermediate: ".

- +	    "'$rc_intermediate'\n");

- +}

- +

- +if ($intermediate) {

- +	info("Using intermediate gcov format\n");

- +	if ($opt_derive_func_data) {

- +		warn("WARNING: --derive-func-data is not compatible with ".

- +		     "intermediate format - ignoring\n");

- +		$opt_derive_func_data = 0;

- +	}

- +}

-  

-  # Determine gcov options

- -$gcov_caps = get_gcov_capabilities();

-  push(@gcov_options, "-b") if ($gcov_caps->{'branch-probabilities'} &&

-  			      ($br_coverage || $func_coverage));

-  push(@gcov_options, "-c") if ($gcov_caps->{'branch-counts'} &&

-  			      $br_coverage);

-  push(@gcov_options, "-a") if ($gcov_caps->{'all-blocks'} &&

- -			      $opt_gcov_all_blocks && $br_coverage);

- +			      $opt_gcov_all_blocks && $br_coverage &&

- +			      !$intermediate);

-  if ($gcov_caps->{'hash-filenames'})

-  {

-  	push(@gcov_options, "-x");

- @@ -599,7 +627,7 @@ foreach my $entry (@data_directory) {

-  	gen_info($entry);

-  }

-  

- -if ($initial && $br_coverage) {

- +if ($initial && $br_coverage && !$intermediate) {

-  	warn("Note: --initial does not generate branch coverage ".

-  	     "data\n");

-  }

- @@ -768,6 +796,7 @@ sub gen_info($)

-  	my $prefix;

-  	my $type;

-  	my $ext;

- +	my $tempdir;

-  

-  	if ($initial) {

-  		$type = "graph";

- @@ -798,16 +827,22 @@ sub gen_info($)

-  		$prefix = "";

-  	}

-  

- +	$tempdir = tempdir(CLEANUP => 1);

- +

-  	# Process all files in list

-  	foreach $file (@file_list) {

-  		# Process file

- -		if ($initial) {

- +		if ($intermediate) {

- +			process_intermediate($file, $prefix, $tempdir);

- +		} elsif ($initial) {

-  			process_graphfile($file, $prefix);

-  		} else {

-  			process_dafile($file, $prefix);

-  		}

-  	}

-  

- +	unlink($tempdir);

- +

-  	# Report whether files were excluded.

-  	if (%excluded_files) {

-  		info("Excluded data for %d files due to include/exclude options\n",

- @@ -1058,10 +1093,12 @@ sub process_dafile($$)

-  

-  	# Try to find base directory automatically if requested by user

-  	if ($rc_auto_base) {

- -		$base_dir = find_base_from_graph($base_dir, $instr, $graph);

- +		$base_dir = find_base_from_source($base_dir,

- +			[ keys(%{$instr}), keys(%{$graph}) ]);

-  	}

-  

- -	($instr, $graph) = adjust_graph_filenames($base_dir, $instr, $graph);

- +	adjust_source_filenames($instr, $base_dir);

- +	adjust_source_filenames($graph, $base_dir);

-  

-  	# Set $object_dir to real location of object files. This may differ

-  	# from $da_dir if the graph file is just a link to the "real" object

- @@ -2017,6 +2054,299 @@ sub read_gcov_file($)

-  }

-  

-  

- +#

- +# read_intermediate_text(gcov_filename, data)

- +#

- +# Read gcov intermediate text format in GCOV_FILENAME and add the resulting

- +# data to DATA in the following format:

- +#

- +# data:      source_filename -> file_data

- +# file_data: concatenated lines of intermediate text data

- +#

- +

- +sub read_intermediate_text($$)

- +{

- +	my ($gcov_filename, $data) = @_;

- +	my $fd;

- +	my $filename;

- +

- +	open($fd, "<", $gcov_filename) or

- +		die("ERROR: Could not read $gcov_filename: $!\n");

- +	while (my $line = <$fd>) {

- +		if ($line =~ /^file:(.*)$/) {

- +			$filename = $1;

- +			chomp($filename);

- +		} elsif (defined($filename)) {

- +			$data->{$filename} .= $line;

- +		}

- +	}

- +	close($fd);

- +}

- +

- +

- +#

- +# intermediate_text_to_info(fd, data, srcdata)

- +#

- +# Write DATA in info format to file descriptor FD.

- +#

- +# data:      filename -> file_data:

- +# file_data: concatenated lines of intermediate text data

- +#

- +# srcdata:   filename -> [ excl, brexcl, checksums ]

- +# excl:      lineno -> 1 for all lines for which to exclude all data

- +# brexcl:    lineno -> 1 for all lines for which to exclude branch data

- +# checksums: lineno -> source code checksum

- +#

- +# Note: To simplify processing, gcov data is not combined here, that is counts

- +#       that appear multiple times for the same lines/branches are not added.

- +#       This is done by lcov/genhtml when reading the data files.

- +#

- +

- +sub intermediate_text_to_info($$$)

- +{

- +	my ($fd, $data, $srcdata) = @_;

- +	my $branch_num = 0;

- +	my $c;

- +

- +	return if (!%{$data});

- +

- +	print($fd "TN:$test_name\n");

- +	for my $filename (keys(%{$data})) {

- +		my ($excl, $brexcl, $checksums);

- +

- +		if (defined($srcdata->{$filename})) {

- +			($excl, $brexcl, $checksums) = @{$srcdata->{$filename}};

- +		}

- +

- +		print($fd "SF:$filename\n");

- +		for my $line (split(/\n/, $data->{$filename})) {

- +			if ($line =~ /^lcount:(\d+),(\d+),?/) {

- +				# lcount:<line>,<count>

- +				# lcount:<line>,<count>,<has_unexecuted_blocks>

- +				if ($checksum && exists($checksums->{$1})) {

- +					$c = ",".$checksums->{$1};

- +				} else {

- +					$c = "";

- +				}

- +				print($fd "DA:$1,$2$c\n") if (!$excl->{$1});

- +

- +				# Intermediate text format does not provide

- +				# branch numbers, and the same branch may appear

- +				# multiple times on the same line (e.g. in

- +				# template instances). Synthesize a branch

- +				# number based on the assumptions:

- +				# a) the order of branches is fixed across

- +				#    instances

- +				# b) an instance starts with an lcount line

- +				$branch_num = 0;

- +			} elsif ($line =~ /^function:(\d+),(\d+),([^,]+)$/) {

- +				next if (!$func_coverage || $excl->{$1});

- +

- +				# function:<line>,<count>,<name>

- +				print($fd "FN:$1,$3\n");

- +				print($fd "FNDA:$2,$3\n");

- +			} elsif ($line =~ /^function:(\d+),\d+,(\d+),([^,]+)$/) {

- +				next if (!$func_coverage || $excl->{$1});

- +

- +				# function:<start_line>,<end_line>,<count>,

- +				#          <name>

- +				print($fd "FN:$1,$3\n");

- +				print($fd "FNDA:$2,$3\n");

- +			} elsif ($line =~ /^branch:(\d+),(taken|nottaken|notexec)/) {

- +				next if (!$br_coverage || $excl->{$1} ||

- +					 $brexcl->{$1});

- +

- +				# branch:<line>,taken|nottaken|notexec

- +				if ($2 eq "taken") {

- +					$c = 1;

- +				} elsif ($2 eq "nottaken") {

- +					$c = 0;

- +				} else {

- +					$c = "-";

- +				}

- +				print($fd "BRDA:$1,0,$branch_num,$c\n");

- +				$branch_num++;

- +			}

- +		}

- +		print($fd "end_of_record\n");

- +	}

- +}

- +

- +

- +sub get_output_fd($$)

- +{

- +	my ($outfile, $file) = @_;

- +	my $fd;

- +

- +	if (!defined($outfile)) {

- +		open($fd, ">", "$file.info") or

- +			die("ERROR: Cannot create file $file.info: $!\n");

- +	} elsif ($outfile eq "-") {

- +		open($fd, ">&STDOUT") or

- +			die("ERROR: Cannot duplicate stdout: $!\n");

- +	} else {

- +		open($fd, ">>", $outfile) or

- +			die("ERROR: Cannot write to file $outfile: $!\n");

- +	}

- +

- +	return $fd;

- +}

- +

- +

- +#

- +# print_gcov_warnings(stderr_file, is_graph, map)

- +#

- +# Print GCOV warnings in file STDERR_FILE to STDERR. If IS_GRAPH is non-zero,

- +# suppress warnings about missing as these are expected. Replace keys found

- +# in MAP with their values.

- +#

- +

- +sub print_gcov_warnings($$$)

- +{

- +	my ($stderr_file, $is_graph, $map) = @_;

- +	my $fd;

- +

- +	if (!open($fd, "<", $stderr_file)) {

- +		warn("WARNING: Could not open GCOV stderr file ".

- +		     "$stderr_file: $!\n");

- +		return;

- +	}

- +	while (my $line = <$fd>) {

- +		next if ($is_graph && $line =~ /cannot open data file/);

- +

- +		for my $key (keys(%{$map})) {

- +			$line =~ s/\Q$key\E/$map->{$key}/g;

- +		}

- +

- +		print(STDERR $line);

- +	}

- +	close($fd);

- +}

- +

- +

- +#

- +# process_intermediate(file, dir, tempdir)

- +#

- +# Create output for a single file (either a data file or a graph file) using

- +# gcov's intermediate option.

- +#

- +

- +sub process_intermediate($$$)

- +{

- +	my ($file, $dir, $tempdir) = @_;

- +	my ($fdir, $fbase, $fext);

- +	my $data_file;

- +	my $errmsg;

- +	my %data;

- +	my $fd;

- +	my $base;

- +	my $srcdata;

- +	my $is_graph = 0;

- +	my ($out, $err, $rc);

- +

- +	info("Processing %s\n", abs2rel($file, $dir));

- +

- +	$file = solve_relative_path($cwd, $file);

- +	($fdir, $fbase, $fext) = split_filename($file);

- +

- +	$is_graph = 1 if (".$fext" eq $graph_file_extension);

- +

- +	if ($is_graph) {

- +		# Process graph file - copy to temp directory to prevent

- +		# accidental processing of associated data file

- +		$data_file = "$tempdir/$fbase$graph_file_extension";

- +		if (!copy($file, $data_file)) {

- +			$errmsg = "ERROR: Could not copy file $file";

- +			goto err;

- +		}

- +	} else {

- +		# Process data file in place

- +		$data_file = $file;

- +	}

- +

- +	# Change directory

- +	if (!chdir($tempdir)) {

- +		$errmsg = "Could not change to directory $tempdir: $!";

- +		goto err;

- +	}

- +

- +	# Run gcov on data file

- +	($out, $err, $rc) = system_no_output(1 + 2 + 4, $gcov_tool,

- +					     $data_file, @gcov_options, "-i");

- +	defined($out) && unlink($out);

- +	if (defined($err)) {

- +		print_gcov_warnings($err, $is_graph, {

- +			$data_file => $file,

- +		});

- +		unlink($err);

- +	}

- +	if ($rc) {

- +		$errmsg = "GCOV failed for $file";

- +		goto err;

- +	}

- +

- +	if ($is_graph) {

- +		# Remove graph file copy

- +		unlink($data_file);

- +	}

- +

- +	# Parse resulting file(s)

- +	for my $gcov_filename (glob("*.gcov")) {

- +		read_intermediate_text($gcov_filename, \%data);

- +		unlink($gcov_filename);

- +	}

- +

- +	if (!%data) {

- +		warn("WARNING: GCOV did not produce any data for $file\n");

- +		return;

- +	}

- +

- +	# Determine base directory

- +	if (defined($base_directory)) {

- +		$base = $base_directory;

- +	} else {

- +		$base = $fdir;

- +

- +		if (is_compat($COMPAT_MODE_LIBTOOL)) {

- +			# Avoid files from .libs dirs

- +			$base =~ s/\.libs$//;

- +		}

- +

- +		# Try to find base directory automatically if requested by user

- +		if ($rc_auto_base) {

- +			$base = find_base_from_source($base, [ keys(%data) ]);

- +		}

- +	}

- +

- +	# Apply base file name to relative source files

- +	adjust_source_filenames(\%data, $base);

- +

- +	# Remove excluded source files

- +	filter_source_files(\%data);

- +

- +	# Get data on exclusion markers and checksums if requested

- +	if (!$no_markers || $checksum) {

- +		$srcdata = get_all_source_data(keys(%data));

- +	}

- +

- +	# Generate output

- +	$fd = get_output_fd($output_filename, $file);

- +	intermediate_text_to_info($fd, \%data, $srcdata);

- +	close($fd);

- +

- +	chdir($cwd);

- +

- +	return;

- +

- +err:

- +	if ($ignore[$ERROR_GCOV]) {

- +		warn("WARNING: $errmsg!\n");

- +	} else {

- +		die("ERROR: $errmsg!\n")

- +	}

- +}

- +

- +

-  # Map LLVM versions to the version of GCC gcov which they emulate.

-  

-  sub map_llvm_version($)

- @@ -2151,8 +2481,12 @@ sub int_handler()

-  #

-  #   MODE & 1: suppress STDOUT

-  #   MODE & 2: suppress STDERR

- +#   MODE & 4: redirect to temporary files instead of suppressing

-  #

- -# Return 0 on success, non-zero otherwise.

- +# Return (stdout, stderr, rc):

- +#    stdout: path to tempfile containing stdout or undef

- +#    stderr: path to tempfile containing stderr or undef

- +#    0 on success, non-zero otherwise

-  #

-  

-  sub system_no_output($@)

- @@ -2161,14 +2495,31 @@ sub system_no_output($@)

-  	my $result;

-  	local *OLD_STDERR;

-  	local *OLD_STDOUT;

- +	my $stdout_file;

- +	my $stderr_file;

- +	my $fd;

-  

-  	# Save old stdout and stderr handles

-  	($mode & 1) && open(OLD_STDOUT, ">>&", "STDOUT");

-  	($mode & 2) && open(OLD_STDERR, ">>&", "STDERR");

-  

- -	# Redirect to /dev/null

- -	($mode & 1) && open(STDOUT, ">", "/dev/null");

- -	($mode & 2) && open(STDERR, ">", "/dev/null");

- +	if ($mode & 4) {

- +		# Redirect to temporary files

- +		if ($mode & 1) {

- +			($fd, $stdout_file) = tempfile(UNLINK => 1);

- +			open(STDOUT, ">", $stdout_file) || warn("$!\n");

- +			close($fd);

- +		}

- +		if ($mode & 2) {

- +			($fd, $stderr_file) = tempfile(UNLINK => 1);

- +			open(STDERR, ">", $stderr_file) || warn("$!\n");

- +			close($fd);

- +		}

- +	} else {

- +		# Redirect to /dev/null

- +		($mode & 1) && open(STDOUT, ">", "/dev/null");

- +		($mode & 2) && open(STDERR, ">", "/dev/null");

- +	}

-   

-  	debug("system(".join(' ', @_).")\n");

-  	system(@_);

- @@ -2181,8 +2532,18 @@ sub system_no_output($@)

-  	# Restore old handles

-  	($mode & 1) && open(STDOUT, ">>&", "OLD_STDOUT");

-  	($mode & 2) && open(STDERR, ">>&", "OLD_STDERR");

- +

- +	# Remove empty output files

- +	if (defined($stdout_file) && -z $stdout_file) {

- +		unlink($stdout_file);

- +		$stdout_file = undef;

- +	}

- +	if (defined($stderr_file) && -z $stderr_file) {

- +		unlink($stderr_file);

- +		$stderr_file = undef;

- +	}

-   

- -	return $result;

- +	return ($stdout_file, $stderr_file, $result);

-  }

-  

-  

- @@ -2260,23 +2621,28 @@ sub apply_config($)

-  

-  

-  #

- -# get_exclusion_data(filename)

- +# get_source_data(filename)

-  #

- -# Scan specified source code file for exclusion markers and return

- -#   linenumber -> 1

- -# for all lines which should be excluded.

- +# Scan specified source code file for exclusion markers and checksums. Return

- +#   ( excl, brexcl, checksums ) where

- +#   excl:      lineno -> 1 for all lines for which to exclude all data

- +#   brexcl:    lineno -> 1 for all lines for which to exclude branch data

- +#   checksums: lineno -> source code checksum

-  #

-  

- -sub get_exclusion_data($)

- +sub get_source_data($)

-  {

-  	my ($filename) = @_;

-  	my %list;

-  	my $flag = 0;

- +	my %brdata;

- +	my $brflag = 0;

- +	my %checksums;

-  	local *HANDLE;

-  

-  	if (!open(HANDLE, "<", $filename)) {

-  		warn("WARNING: could not open $filename\n");

- -		return undef;

- +		return;

-  	}

-  	while (<HANDLE>) {

-  		if (/$EXCL_STOP/) {

- @@ -2287,14 +2653,62 @@ sub get_exclusion_data($)

-  		if (/$excl_line/ || $flag) {

-  			$list{$.} = 1;

-  		}

- +		if (/$EXCL_BR_STOP/) {

- +			$brflag = 0;

- +		} elsif (/$EXCL_BR_START/) {

- +			$brflag = 1;

- +		}

- +		if (/$excl_br_line/ || $brflag) {

- +			$brdata{$.} = 1;

- +		}

- +		if ($checksum) {

- +			chomp();

- +			$checksums{$.} = md5_base64($_);

- +		}

-  	}

-  	close(HANDLE);

-  

- -	if ($flag) {

- +	if ($flag || $brflag) {

-  		warn("WARNING: unterminated exclusion section in $filename\n");

-  	}

-  

- -	return \%list;

- +	return (\%list, \%brdata, \%checksums);

- +}

- +

- +

- +#

- +# get_all_source_data(filenames)

- +#

- +# Scan specified source code files for exclusion markers and return

- +#   filename -> [ excl, brexcl, checksums ]

- +#   excl:      lineno -> 1 for all lines for which to exclude all data

- +#   brexcl:    lineno -> 1 for all lines for which to exclude branch data

- +#   checksums: lineno -> source code checksum

- +#

- +

- +sub get_all_source_data(@)

- +{

- +	my @filenames = @_;

- +	my %data;

- +	my $failed = 0;

- +

- +	for my $filename (@filenames) {

- +		my @d;

- +		next if (exists($data{$filename}));

- +

- +		@d = get_source_data($filename);

- +		if (@d) {

- +			$data{$filename} = [ @d ];

- +		} else {

- +			$failed = 1;

- +		}

- +	}

- +

- +	if ($failed) {

- +		warn("WARNING: some exclusion markers may be ignored\n");

- +	}

- +

- +	return \%data;

-  }

-  

-  

- @@ -2318,35 +2732,17 @@ sub apply_exclusion_data($$)

-  {

-  	my ($instr, $graph) = @_;

-  	my $filename;

- -	my %excl_data;

- -	my $excl_read_failed = 0;

- +	my $excl_data;

-  

- -	# Collect exclusion marker data

- -	foreach $filename (sort_uniq_lex(keys(%{$graph}), keys(%{$instr}))) {

- -		my $excl = get_exclusion_data($filename);

- -

- -		# Skip and note if file could not be read

- -		if (!defined($excl)) {

- -			$excl_read_failed = 1;

- -			next;

- -		}

- -

- -		# Add to collection if there are markers

- -		$excl_data{$filename} = $excl if (keys(%{$excl}) > 0);

- -	}

- -

- -	# Warn if not all source files could be read

- -	if ($excl_read_failed) {

- -		warn("WARNING: some exclusion markers may be ignored\n");

- -	}

- +	($excl_data) = get_all_source_data(keys(%{$graph}), keys(%{$instr}));

-  

-  	# Skip if no markers were found

- -	return ($instr, $graph) if (keys(%excl_data) == 0);

- +	return ($instr, $graph) if (!%$excl_data);

-  

-  	# Apply exclusion marker data to graph

- -	foreach $filename (keys(%excl_data)) {

- +	foreach $filename (keys(%$excl_data)) {

-  		my $function_data = $graph->{$filename};

- -		my $excl = $excl_data{$filename};

- +		my $excl = $excl_data->{$filename}->[0];

-  		my $function;

-  

-  		next if (!defined($function_data));

- @@ -2384,9 +2780,9 @@ sub apply_exclusion_data($$)

-  	}

-  

-  	# Apply exclusion marker data to instr

- -	foreach $filename (keys(%excl_data)) {

- +	foreach $filename (keys(%$excl_data)) {

-  		my $line_data = $instr->{$filename};

- -		my $excl = $excl_data{$filename};

- +		my $excl = $excl_data->{$filename}->[0];

-  		my $line;

-  		my @new_data;

-  

- @@ -2468,10 +2864,12 @@ sub process_graphfile($$)

-  

-  	# Try to find base directory automatically if requested by user

-  	if ($rc_auto_base) {

- -		$base_dir = find_base_from_graph($base_dir, $instr, $graph);

- +		$base_dir = find_base_from_source($base_dir,

- +			[ keys(%{$instr}), keys(%{$graph}) ]);

-  	}

-  

- -	($instr, $graph) = adjust_graph_filenames($base_dir, $instr, $graph);

- +	adjust_source_filenames($instr, $base_dir);

- +	adjust_source_filenames($graph, $base_dir);

-  

-  	if (!$no_markers) {

-  		# Apply exclusion marker data to graph file data

- @@ -2767,11 +3165,11 @@ sub parent_dir($)

-  }

-  

-  #

- -# find_base_from_graph(base_dir, instr, graph)

- +# find_base_from_source(base_dir, source_files)

-  #

- -# Try to determine the base directory of the graph file specified by INSTR

- -# and GRAPH. The base directory is the base for all relative filenames in

- -# the graph file. It is defined by the current working directory at time

- +# Try to determine the base directory of the object file built from

- +# SOURCE_FILES. The base directory is the base for all relative filenames in

- +# the gcov data. It is defined by the current working directory at time

-  # of compiling the source file.

-  #

-  # This function implements a heuristic which relies on the following

- @@ -2781,16 +3179,16 @@ sub parent_dir($)

-  # - files by the same name are not present in multiple parent directories

-  #

-  

- -sub find_base_from_graph($$$)

- +sub find_base_from_source($$)

-  {

- -	my ($base_dir, $instr, $graph) = @_;

- +	my ($base_dir, $source_files) = @_;

-  	my $old_base;

-  	my $best_miss;

-  	my $best_base;

-  	my %rel_files;

-  

-  	# Determine list of relative paths

- -	foreach my $filename (keys(%{$instr}), keys(%{$graph})) {

- +	foreach my $filename (@$source_files) {

-  		next if (file_name_is_absolute($filename));

-  

-  		$rel_files{$filename} = 1;

- @@ -2829,17 +3227,17 @@ sub find_base_from_graph($$$)

-  }

-  

-  #

- -# adjust_graph_filenames(base_dir, instr, graph)

- +# adjust_source_filenames(hash, base_dir)

-  #

- -# Make relative paths in INSTR and GRAPH absolute and apply

- -# geninfo_adjust_src_path setting to graph file data.

- +# Transform all keys of HASH to absolute form and apply requested

- +# transformations.

-  #

-  

- -sub adjust_graph_filenames($$$)

- +sub adjust_source_filenames($$$)

-  {

- -	my ($base_dir, $instr, $graph) = @_;

- +	my ($hash, $base_dir) = @_;

-  

- -	foreach my $filename (keys(%{$instr})) {

- +	foreach my $filename (keys(%{$hash})) {

-  		my $old_filename = $filename;

-  

-  		# Convert to absolute canonical form

- @@ -2851,28 +3249,50 @@ sub adjust_graph_filenames($$$)

-  		}

-  

-  		if ($filename ne $old_filename) {

- -			$instr->{$filename} = delete($instr->{$old_filename});

- +			$hash->{$filename} = delete($hash->{$old_filename});

-  		}

-  	}

- +}

-  

- -	foreach my $filename (keys(%{$graph})) {

- -		my $old_filename = $filename;

-  

- -		# Make absolute

- -		# Convert to absolute canonical form

- -		$filename = solve_relative_path($base_dir, $filename);

- +#

- +# filter_source_files(hash)

- +#

- +# Remove unwanted source file data from HASH.

- +#

-  

- -		# Apply adjustment

- -		if (defined($adjust_src_pattern)) {

- -			$filename =~ s/$adjust_src_pattern/$adjust_src_replace/g;

- +sub filter_source_files($)

- +{

- +	my ($hash) = @_;

- +

- +	foreach my $filename (keys(%{$hash})) {

- +		# Skip external files if requested

- +		goto del if (!$opt_external && is_external($filename));

- +

- +		# Apply include patterns

- +		if (@include_patterns) {

- +			my $keep;

- +

- +			foreach my $pattern (@include_patterns) {

- +				if ($filename =~ (/^$pattern$/)) {

- +					$keep = 1;

- +					last;

- +				}

- +			}

- +			goto del if (!$keep);

-  		}

-  

- -		if ($filename ne $old_filename) {

- -			$graph->{$filename} = delete($graph->{$old_filename});

- +		# Apply exclude patterns

- +		foreach my $pattern (@exclude_patterns) {

- +			goto del if ($filename =~ (/^$pattern$/));

-  		}

- -	}

- +		next;

-  

- -	return ($instr, $graph);

- +del:

- +		# Remove file data

- +		delete($hash->{$filename});

- +		$excluded_files{$filename} = 1;

- +	}

-  }

-  

-  #

- @@ -3784,6 +4204,7 @@ sub get_gcov_capabilities()

-  		'c' => 'branch-counts',

-  		'f' => 'function-summaries',

-  		'h' => 'help',

- +		'i' => 'intermediate-format',

-  		'l' => 'long-file-names',

-  		'n' => 'no-output',

-  		'o' => 'object-directory',

- diff --git a/lcovrc b/lcovrc

- index 40f364f..bd4bc3b 100644

- --- a/lcovrc

- +++ b/lcovrc

- @@ -134,6 +134,9 @@ genhtml_desc_html=0

-  # when collecting coverage data.

-  geninfo_auto_base = 1

-  

- +# Use gcov intermediate format? Valid values are 0, 1, auto

- +geninfo_intermediate = auto

- +

-  # Directory containing gcov kernel files

-  # lcov_gcov_dir = /proc/gcov

-  

- diff --git a/man/lcovrc.5 b/man/lcovrc.5

- index a6d654b..07d35ff 100644

- --- a/man/lcovrc.5

- +++ b/man/lcovrc.5

- @@ -223,6 +223,11 @@ geninfo_compat_libtool = 0

-  geninfo_auto_base = 1

-  .br

-  

- +# Use gcov intermediate format? Valid values are 0, 1, auto

- +.br

- +geninfo_intermediate = auto

- +.br

- +

-  # Directory containing gcov kernel files

-  .br

-  lcov_gcov_dir = /proc/gcov

- @@ -789,6 +794,25 @@ located, and in addition, is different between files of the same project.

-  Default is 1.

-  .PP

-  

- +.BR geninfo_intermediate " ="

- +.IR 0 | 1 | auto

- +.IP

- +Specify whether to use gcov intermediate format

- +.br

- +

- +Use this option to control whether geninfo should use the gcov intermediate

- +format while collecting coverage data. The use of the gcov intermediate format

- +should increase processing speed. It also provides branch coverage data when

- +using the \-\-initial command line option.

- +.br

- +

- +Valid values are 0 for off, 1 for on, and "auto" to let geninfo automatically

- +use immediate format when supported by gcov.

- +.br

- +

- +Default is "auto".

- +.PP

- +

-  .BR lcov_gcov_dir " ="

-  .I path_to_kernel_coverage_data

-  .IP

- -- 

- 2.21.0

- 

@@ -1,244 +0,0 @@ 

- From 75fbae1cfc5027f818a0bb865bf6f96fab3202da Mon Sep 17 00:00:00 2001

- From: Peter Oberparleiter <oberpar@linux.ibm.com>

- Date: Fri, 24 May 2019 17:16:56 +0200

- Subject: [PATCH 2/2] geninfo: Add intermediate JSON format support

- 

- This change adds support for parsing the output of gcov's intermediate

- JSON file format as implemented by GCC version 9.

- 

- Note: The way that the intermediate file format support is implemented

- in geninfo removes the need to parse .gcno files directly. Since geninfo

- does not include support for parsing GCC 9 .gcno files, using the

- intermediate format is the only option for geninfo to collect coverage

- data generated by GCC version 9.

- 

- Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>

- ---

-  bin/geninfo | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++-

-  1 file changed, 160 insertions(+), 2 deletions(-)

- 

- diff --git a/bin/geninfo b/bin/geninfo

- index 5453356..4e7a293 100755

- --- a/bin/geninfo

- +++ b/bin/geninfo

- @@ -59,6 +59,9 @@ use File::Copy qw(copy);

-  use Getopt::Long;

-  use Digest::MD5 qw(md5_base64);

-  use Cwd qw/abs_path/;

- +use PerlIO::gzip;

- +use JSON qw(decode_json);

- +

-  if( $^O eq "msys" )

-  {

-  	require File::Spec::Win32;

- @@ -474,7 +477,8 @@ if ($rc_intermediate eq "0") {

-  	$intermediate = 1;

-  } elsif (lc($rc_intermediate) eq "auto") {

-  	# Use intermediate format if supported by gcov

- -	$intermediate = $gcov_caps->{'intermediate-format'} ? 1 : 0;

- +	$intermediate = ($gcov_caps->{'intermediate-format'} ||

- +			 $gcov_caps->{'json-format'}) ? 1 : 0;

-  } else {

-  	die("ERROR: invalid value for geninfo_intermediate: ".

-  	    "'$rc_intermediate'\n");

- @@ -2084,6 +2088,48 @@ sub read_intermediate_text($$)

-  }

-  

-  

- +#

- +# read_intermediate_json(gcov_filename, data, basedir_ref)

- +#

- +# Read gcov intermediate JSON format in GCOV_FILENAME and add the resulting

- +# data to DATA in the following format:

- +#

- +# data:      source_filename -> file_data

- +# file_data: GCOV JSON data for file

- +#

- +# Also store the value for current_working_directory to BASEDIR_REF.

- +#

- +

- +sub read_intermediate_json($$$)

- +{

- +	my ($gcov_filename, $data, $basedir_ref) = @_;

- +	my $fd;

- +	my $text;

- +	my $json;

- +

- +	open($fd, "<:gzip", $gcov_filename) or

- +		die("ERROR: Could not read $gcov_filename: $!\n");

- +	local $/;

- +	$text = <$fd>;

- +	close($fd);

- +

- +	$json = decode_json($text);

- +	if (!defined($json) || !exists($json->{"files"}) ||

- +	    ref($json->{"files"} ne "ARRAY")) {

- +		die("ERROR: Unrecognized JSON output format in ".

- +		    "$gcov_filename\n");

- +	}

- +

- +	$$basedir_ref = $json->{"current_working_directory"};

- +

- +	for my $file (@{$json->{"files"}}) {

- +		my $filename = $file->{"file"};

- +

- +		$data->{$filename} = $file;

- +	}

- +}

- +

- +

-  #

-  # intermediate_text_to_info(fd, data, srcdata)

-  #

- @@ -2173,6 +2219,104 @@ sub intermediate_text_to_info($$$)

-  }

-  

-  

- +#

- +# intermediate_json_to_info(fd, data, srcdata)

- +#

- +# Write DATA in info format to file descriptor FD.

- +#

- +# data:      filename -> file_data:

- +# file_data: GCOV JSON data for file

- +#

- +# srcdata:   filename -> [ excl, brexcl, checksums ]

- +# excl:      lineno -> 1 for all lines for which to exclude all data

- +# brexcl:    lineno -> 1 for all lines for which to exclude branch data

- +# checksums: lineno -> source code checksum

- +#

- +# Note: To simplify processing, gcov data is not combined here, that is counts

- +#       that appear multiple times for the same lines/branches are not added.

- +#       This is done by lcov/genhtml when reading the data files.

- +#

- +

- +sub intermediate_json_to_info($$$)

- +{

- +	my ($fd, $data, $srcdata) = @_;

- +	my $branch_num = 0;

- +

- +	return if (!%{$data});

- +

- +	print($fd "TN:$test_name\n");

- +	for my $filename (keys(%{$data})) {

- +		my ($excl, $brexcl, $checksums);

- +		my $file_data = $data->{$filename};

- +

- +		if (defined($srcdata->{$filename})) {

- +			($excl, $brexcl, $checksums) = @{$srcdata->{$filename}};

- +		}

- +

- +		print($fd "SF:$filename\n");

- +

- +		# Function data

- +		if ($func_coverage) {

- +			for my $d (@{$file_data->{"functions"}}) {

- +				my $line = $d->{"start_line"};

- +				my $count = $d->{"execution_count"};

- +				my $name = $d->{"name"};

- +

- +				next if (!defined($line) || !defined($count) ||

- +					 !defined($name) || $excl->{$line});

- +

- +				print($fd "FN:$line,$name\n");

- +				print($fd "FNDA:$count,$name\n");

- +			}

- +		}

- +

- +		# Line data

- +		for my $d (@{$file_data->{"lines"}}) {

- +			my $line = $d->{"line_number"};

- +			my $count = $d->{"count"};

- +			my $c;

- +			my $branches = $d->{"branches"};

- +			my $unexec = $d->{"unexecuted_block"};

- +

- +			next if (!defined($line) || !defined($count) ||

- +				 $excl->{$line});

- +

- +			if (defined($unexec) && $unexec && $count == 0) {

- +				$unexec = 1;

- +			} else {

- +				$unexec = 0;

- +			}

- +

- +			if ($checksum && exists($checksums->{$line})) {

- +				$c = ",".$checksums->{$line};

- +			} else {

- +				$c = "";

- +			}

- +			print($fd "DA:$line,$count$c\n");

- +

- +			$branch_num = 0;

- +			# Branch data

- +			if ($br_coverage && !$brexcl->{$line}) {

- +				for my $b (@$branches) {

- +					my $brcount = $b->{"count"};

- +

- +					if (!defined($brcount) || $unexec) {

- +						$brcount = "-";

- +					}

- +					print($fd "BRDA:$line,0,$branch_num,".

- +					      "$brcount\n");

- +

- +					$branch_num++;

- +				}

- +			}

- +

- +		}

- +

- +		print($fd "end_of_record\n");

- +	}

- +}

- +

- +

-  sub get_output_fd($$)

-  {

-  	my ($outfile, $file) = @_;

- @@ -2243,6 +2387,8 @@ sub process_intermediate($$$)

-  	my $srcdata;

-  	my $is_graph = 0;

-  	my ($out, $err, $rc);

- +	my $json_basedir;

- +	my $json_format;

-  

-  	info("Processing %s\n", abs2rel($file, $dir));

-  

- @@ -2296,6 +2442,12 @@ sub process_intermediate($$$)

-  		unlink($gcov_filename);

-  	}

-  

- +	for my $gcov_filename (glob("*.gcov.json.gz")) {

- +		read_intermediate_json($gcov_filename, \%data, \$json_basedir);

- +		unlink($gcov_filename);

- +		$json_format = 1;

- +	}

- +

-  	if (!%data) {

-  		warn("WARNING: GCOV did not produce any data for $file\n");

-  		return;

- @@ -2304,6 +2456,8 @@ sub process_intermediate($$$)

-  	# Determine base directory

-  	if (defined($base_directory)) {

-  		$base = $base_directory;

- +	} elsif (defined($json_basedir)) {

- +		$base = $json_basedir;

-  	} else {

-  		$base = $fdir;

-  

- @@ -2331,7 +2485,11 @@ sub process_intermediate($$$)

-  

-  	# Generate output

-  	$fd = get_output_fd($output_filename, $file);

- -	intermediate_text_to_info($fd, \%data, $srcdata);

- +	if ($json_format) {

- +		intermediate_json_to_info($fd, \%data, $srcdata);

- +	} else {

- +		intermediate_text_to_info($fd, \%data, $srcdata);

- +	}

-  	close($fd);

-  

-  	chdir($cwd);

- -- 

- 2.21.0

- 

file modified
+40 -9
@@ -1,14 +1,12 @@ 

  Name: lcov

- Version: 1.14

- Release: 10%{?dist}

+ Version: 2.0

+ Release: 1%{?dist}

  

  Summary: LTP GCOV extension code coverage tool

  License: GPL-2.0-or-later

  

  URL: https://github.com/linux-test-project/lcov/

  Source0: https://github.com/linux-test-project/lcov/releases/download/v%{version}/lcov-%{version}.tar.gz

- Patch1: 0001-geninfo-Add-intermediate-text-format-support.patch

- Patch2: 0002-geninfo-Add-intermediate-JSON-format-support.patch

  

  BuildArch: noarch

  BuildRequires: perl-generators
@@ -18,6 +16,11 @@ 

  Requires: /usr/bin/gcov

  Requires: /usr/bin/find

  Requires: perl(GD::Image)

+ Requires: perl(JSON::XS)

+ 

+ # lcovutil.pm is a private helper file

+ %global __requires_exclude ^perl\\(lcovutil\\)$

+ %global __provides_exclude ^perl.*$

  

  %description

  LCOV is an extension of GCOV, a GNU tool which provides information
@@ -27,18 +30,46 @@ 

  HTML output and support for large projects.

  

  %prep

- %autosetup -S git_am

+ %autosetup

  

  %install

- make install DESTDIR=$RPM_BUILD_ROOT BIN_DIR=%{_bindir} MAN_DIR=%{_mandir} CFG_DIR=%{_sysconfdir}

+ make install DESTDIR=$RPM_BUILD_ROOT PREFIX=%{_prefix} \

+      CFG_DIR=%{_sysconfdir} LIB_DIR=%{_datadir}/lcov

  

  %files

- %{_bindir}/*

- %{_mandir}/man1/*

- %{_mandir}/man5/*

+ %{_bindir}/gendesc

+ %{_bindir}/genhtml

+ %{_bindir}/geninfo

+ %{_bindir}/genpng

+ %{_bindir}/lcov

+ %{_mandir}/man1/gendesc.1*

+ %{_mandir}/man1/genhtml.1*

+ %{_mandir}/man1/geninfo.1*

+ %{_mandir}/man1/genpng.1*

+ %{_mandir}/man1/lcov.1*

+ %{_mandir}/man5/lcovrc.5*

+ %dir %{_datadir}/lcov

+ %dir %{_datadir}/lcov/support-scripts

+ %{_datadir}/lcov/lcovutil.pm

+ %{_datadir}/lcov/support-scripts/analyzeInfoFiles

+ %{_datadir}/lcov/support-scripts/criteria

+ %{_datadir}/lcov/support-scripts/get_signature

+ %{_datadir}/lcov/support-scripts/getp4version

+ %{_datadir}/lcov/support-scripts/gitblame

+ %{_datadir}/lcov/support-scripts/gitdiff

+ %{_datadir}/lcov/support-scripts/p4annotate

+ %{_datadir}/lcov/support-scripts/p4udiff

+ %{_datadir}/lcov/support-scripts/py2lcov

+ %{_datadir}/lcov/support-scripts/spreadsheet.py

  %config(noreplace) %attr(0644,root,root) %{_sysconfdir}/lcovrc

  

  %changelog

+ * Mon Nov 27 2023 Terje Rosten <terje.rosten@ntnu.no> - 2.0-1

+ - 2.0

+ - Use explicit file listing

+ - Remove upstream patches

+ - Ship new files

+ 

  * Thu Jul 20 2023 Fedora Release Engineering <releng@fedoraproject.org> - 1.14-10

  - Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild

  

file modified
+1 -1
@@ -1,1 +1,1 @@ 

- SHA512 (lcov-1.14.tar.gz) = 2d60c3a63e300dda96171c432fe304840acc76bf6275f60934d08e80765f9f85671e8b77bfed758fc45842a80156586dc0d67c42c9f215f4f163840fc5cf65bc

+ SHA512 (lcov-2.0.tar.gz) = b19b6debc93c0de0e7e5b2aaffa6c74d20a1313ea4d20d8731c6a5ea7f4cc40933316d28ef791c91fdc12ca77c9449a388405f3dc0793588e366b72f596ab49b

no initial comment

Can you set LIB_DIR=%{_datadir}/lcov, as the lcovutil.pm script really doesn't belong under /usr/lib

We need to add

# lcovutil.pm is a private helper file
%define __requires_exclude ^perl\\(lcovutil\\)$
%define __provides_exclude ^perl.*$

to get rid of bogus perl deps

We need a 'Requires: perl(JSON::XS)' too, since the auto-dep script fails to notice the JSON deps (see README.md for list)

A few minor points, but basically looks good

Can you set LIB_DIR=%{_datadir}/lcov, as the lcovutil.pm script really doesn't belong under /usr/lib

Then I need to patch every bin too, but ok.

Can you set LIB_DIR=%{_datadir}/lcov, as the lcovutil.pm script really doesn't belong under /usr/lib

Then I need to patch every bin too, but ok.

I don't believe that's needed actually - their Makefile seems to pass every script through a "fix.pl" program that will replace this path automagically.

Can you set LIB_DIR=%{_datadir}/lcov, as the lcovutil.pm script really doesn't belong under /usr/lib

Then I need to patch every bin too, but ok.

I don't believe that's needed actually - their Makefile seems to pass every script through a "fix.pl" program that will replace this path automagically.

Ok, :cool:

1 new commit added

  • Add perl dep filtering as shipped *.pm is private
7 months ago

You want squashed commits or as is?

Prefer it squashed, since AFAIK, Pagure doesn't let me squash on merge .

rebased onto 153a97f

7 months ago

Prefer it squashed, since AFAIK, Pagure doesn't let me squash on merge .

Fixed.

Pull-Request has been merged by berrange

7 months ago

I'm building into rawhide and also F39.