| Index: third_party/lcov/bin/mcov
|
| ===================================================================
|
| --- third_party/lcov/bin/mcov (revision 0)
|
| +++ third_party/lcov/bin/mcov (revision 0)
|
| @@ -0,0 +1,289 @@
|
| +#!/usr/bin/perl -w
|
| +#
|
| +# mcov: script to convert gcov data to lcov format on Mac.
|
| +#
|
| +# Based on lcov (http://ltp.sourceforge.net/coverage/lcov.php)
|
| +# Written by ajeya at google dot com.
|
| +#
|
| +# usage:
|
| +# mcov --directory <base directory> --output <output file> --verbose <level>
|
| +#
|
| +
|
| +use strict;
|
| +
|
| +use Cwd;
|
| +use File::Basename;
|
| +use File::Find;
|
| +use File::Spec::Functions;
|
| +use Getopt::Long;
|
| +
|
| +# function prototypes
|
| +sub process_dafile(@);
|
| +sub canonical_path(@);
|
| +sub split_filename(@);
|
| +sub read_gcov_header(@);
|
| +sub read_gcov_file(@);
|
| +
|
| +# scalars with default values
|
| +my $directory = Cwd::abs_path(Cwd::getcwd);
|
| +my $data_file_extension = ".gcda";
|
| +my $output_filename = "output.lcov";
|
| +my $gcov_tool = "/usr/bin/gcov";
|
| +my $verbosity = 0;
|
| +
|
| +# TODO(ajeya): GetOptions doesn't handle case where the script is called with
|
| +# no arguments. This needs to be fixed.
|
| +my $result = GetOptions("directory|d=s" => \$directory,
|
| + "output|o=s" => \$output_filename,
|
| + "verbose" => \$verbosity);
|
| +if (!$result) {
|
| + print "Usage: $0 --directory <base directory> --output <output file>";
|
| + print " [--verbose <level>]\n";
|
| + exit(1);
|
| +}
|
| +
|
| +# convert the directory path to absolute path.
|
| +$directory = Cwd::abs_path($directory);
|
| +
|
| +# convert the output file path to absolute path.
|
| +$output_filename = Cwd::abs_path($output_filename);
|
| +
|
| +# open file for output
|
| +open(INFO_HANDLE, ">$output_filename");
|
| +
|
| +my @file_list; # scalar to hold the list of all gcda files.
|
| +if (-d $directory) {
|
| + printf("Scanning $directory for $data_file_extension files ...\n");
|
| + find(sub {
|
| + my $file = $_;
|
| + if ($file =~ m/\Q$data_file_extension\E$/i) {
|
| + push(@file_list, Cwd::abs_path($file));
|
| + }},
|
| + $directory);
|
| + printf("Found %d data files in %s\n", $#file_list + 1, $directory);
|
| +}
|
| +
|
| +# Process all files in list
|
| +foreach my $file (@file_list) {
|
| + process_dafile($file);
|
| +}
|
| +close(INFO_HANDLE);
|
| +
|
| +# Remove the misc gcov files that are created.
|
| +my @gcov_list = glob("*.gcov");
|
| +foreach my $gcov_file (@gcov_list) {
|
| + unlink($gcov_file);
|
| +}
|
| +
|
| +exit(0);
|
| +
|
| +# end of script
|
| +
|
| +# process_dafile:
|
| +# argument(s): a file path with gcda extension
|
| +# returns: void
|
| +# This method calls gcov to generate the coverage data and write the output in
|
| +# lcov format to the output file.
|
| +sub process_dafile(@) {
|
| + my ($filename) = @_;
|
| + print("Processing $filename ...\n");
|
| +
|
| + my $da_filename; # Name of data file to process
|
| + my $base_name; # data filename without ".da/.gcda" extension
|
| + my $gcov_error; # Error code of gcov tool
|
| + my $object_dir; # Directory containing all object files
|
| + my $gcov_file; # Name of a .gcov file
|
| + my @gcov_data; # Contents of a .gcov file
|
| + my @gcov_list; # List of generated .gcov files
|
| + my $base_dir; # Base directory for current da file
|
| + local *OLD_STDOUT; # Handle to store STDOUT temporarily
|
| +
|
| + # Get directory and basename of data file
|
| + ($base_dir, $base_name) = split_filename(canonical_path($filename));
|
| +
|
| + # Check for writable $base_dir (gcov will try to write files there)
|
| + if (!-w $base_dir) {
|
| + print("ERROR: cannot write to directory $base_dir\n");
|
| + return;
|
| + }
|
| +
|
| + # Construct name of graph file
|
| + $da_filename = File::Spec::Functions::catfile($base_dir,
|
| + join(".", $base_name, "gcno"));
|
| +
|
| + # Ignore empty graph file (e.g. source file with no statement)
|
| + if (-z $da_filename) {
|
| + warn("WARNING: empty $da_filename (skipped)\n");
|
| + return;
|
| + }
|
| +
|
| + # Set $object_dir to real location of object files. This may differ
|
| + # from $base_dir if the graph file is just a link to the "real" object
|
| + # file location.
|
| + $object_dir = dirname($da_filename);
|
| +
|
| + # Save the current STDOUT to OLD_STDOUT and set STDOUT to /dev/null to mute
|
| + # standard output.
|
| + if (!$verbosity) {
|
| + open(OLD_STDOUT, ">>&STDOUT");
|
| + open(STDOUT, ">/dev/null");
|
| + }
|
| +
|
| + # run gcov utility with the supplied gcno file and object directory.
|
| + $gcov_error = system($gcov_tool, $da_filename, "-o", $object_dir);
|
| +
|
| + # Restore STDOUT if we changed it before.
|
| + if (!$verbosity) {
|
| + open(STDOUT, ">>&OLD_STDOUT");
|
| + }
|
| +
|
| + if ($gcov_error) {
|
| + warn("WARNING: GCOV failed for $da_filename!\n");
|
| + return;
|
| + }
|
| +
|
| + # Collect data from resulting .gcov files and create .info file
|
| + @gcov_list = glob("*.gcov");
|
| + # Check for files
|
| + if (!scalar(@gcov_list)) {
|
| + warn("WARNING: gcov did not create any files for $da_filename!\n");
|
| + }
|
| +
|
| + foreach $gcov_file (@gcov_list) {
|
| + my $source_filename = read_gcov_header($gcov_file);
|
| +
|
| + if (!defined($source_filename)) {
|
| + next;
|
| + }
|
| +
|
| + $source_filename = canonical_path($source_filename);
|
| +
|
| + # Read in contents of gcov file
|
| + @gcov_data = read_gcov_file($gcov_file);
|
| +
|
| + # Skip empty files
|
| + if (!scalar(@gcov_data)) {
|
| + warn("WARNING: skipping empty file $gcov_file\n");
|
| + unlink($gcov_file);
|
| + next;
|
| + }
|
| +
|
| + print(INFO_HANDLE "SF:", Cwd::abs_path($source_filename), "\n");
|
| +
|
| + # Write coverage information for each instrumented line
|
| + # Note: @gcov_content contains a list of (flag, count, source)
|
| + # tuple for each source code line
|
| + while (@gcov_data) {
|
| + # Check for instrumented line
|
| + if ($gcov_data[0]) {
|
| + print(INFO_HANDLE "DA:", $gcov_data[3], ",", $gcov_data[1], "\n");
|
| + }
|
| + # Remove already processed data from array
|
| + splice(@gcov_data,0,4);
|
| + }
|
| + print(INFO_HANDLE "end_of_record\n");
|
| +
|
| + # Remove .gcov file after processing
|
| + unlink($gcov_file);
|
| + } #end for_each
|
| +}
|
| +
|
| +# canonical_path:
|
| +# argument(s): any file path
|
| +# returns: the file path as a string
|
| +#
|
| +# clean up the file path being passed.
|
| +sub canonical_path(@) {
|
| + my ($filename) = @_;
|
| + return (File::Spec::Functions::canonpath($filename));
|
| +}
|
| +
|
| +# split_filename:
|
| +# argument(s): any file path
|
| +# returns: an array with the path components
|
| +#
|
| +# splits the file path into path and filename (with no extension).
|
| +sub split_filename(@){
|
| + my ($filename) = @_;
|
| + my ($base, $path, $ext) = File::Basename::fileparse($filename, '\.[^\.]*');
|
| + return ($path, $base);
|
| +}
|
| +
|
| +# read_gcov_header:
|
| +# argument(s): path to gcov file
|
| +# returns: an array the contens of the gcov header.
|
| +#
|
| +# reads the gcov file and returns the parsed contents of a gcov header as an
|
| +# array.
|
| +sub read_gcov_header(@) {
|
| + my ($filename) = @_;
|
| + my $source;
|
| + local *INPUT;
|
| +
|
| + if (!open(INPUT, $filename)) {
|
| + warn("WARNING: cannot read $filename!\n");
|
| + return (undef,undef);
|
| + }
|
| +
|
| + my @lines = <INPUT>;
|
| + foreach my $line (@lines) {
|
| + chomp($line);
|
| + # check for lines with source string.
|
| + if ($line =~ /^\s+-:\s+0:Source:(.*)$/) {
|
| + # Source: header entry
|
| + $source = $1;
|
| + } else {
|
| + last;
|
| + }
|
| + }
|
| + close(INPUT);
|
| + return $source;
|
| +}
|
| +
|
| +# read_gcov_file:
|
| +# argument(s): path to gcov file
|
| +# returns: an array with the contents of the gcov file.
|
| +#
|
| +# reads the gcov file and returns the parsed contents of a gcov file
|
| +# as an array.
|
| +sub read_gcov_file(@) {
|
| + my ($filename) = @_;
|
| + my @result = ();
|
| + my $number;
|
| + local *INPUT;
|
| +
|
| + ## TODO(ajeya): Exit more gracefully here.
|
| + open(INPUT, $filename) or die("ERROR: cannot read $filename!\n");
|
| +
|
| + # Parse gcov output and populate the array
|
| + my @lines = <INPUT>;
|
| + foreach my $line (@lines) {
|
| + chomp($line);
|
| + if ($line =~ /^\s*([^:]+):\s*(\d+?):(.*)$/) {
|
| + # <exec count>:<line number>:<source code>
|
| +
|
| + if ($1 eq "-") {
|
| + # Uninstrumented line
|
| + push(@result, 0);
|
| + push(@result, 0);
|
| + push(@result, $3);
|
| + push(@result, $2);
|
| + } elsif ($2 eq "0") {
|
| + #ignore comments and other header info
|
| + } else {
|
| + # Source code execution data
|
| + $number = $1;
|
| + # Check for zero count
|
| + if ($number eq "#####") {
|
| + $number = 0;
|
| + }
|
| + push(@result, 1);
|
| + push(@result, $number);
|
| + push(@result, $3);
|
| + push(@result, $2);
|
| + }
|
| + }
|
| + }
|
| + close(INPUT);
|
| + return @result;
|
| +}
|
|
|
| Property changes on: third_party/lcov/bin/mcov
|
| ___________________________________________________________________
|
| Name: svn:executable
|
| + *
|
|
|
|
|