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 |
+ * |