Files
valgrind/auxprogs/compare-build-logs
Florian Krohm d7811e3de7 Add script. Comes in handy when messing with the build system
to make sure no compiler flags get lost (as they did at some
point in the past).


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@14797
2014-12-03 22:48:29 +00:00

197 lines
4.9 KiB
Perl
Executable File

#!/usr/bin/env perl
# Lame script to compare two build logs.
#
# The script intercepts directory changes and compiler invocations and
# compares the compiler invocations for equality. Equality is defined
# as "same options in both invocations ignoring order". So we only test
# a necessary condition.
#
# Both builds must be configured with the same --prefix. Otherwise,
# the value of -DVG_LIBDIR= will differ. They also need to use the same
# compiler.
use Getopt::Long;
use strict;
use warnings;
my $prog_name = "compare-build-logs";
my $usage=<<EOF;
USAGE
$prog_name log1 log2
[--gcc] intercept GCC invocations (this is default)
[--clang] intercept clang invocations
[-v] verbose mode
log-file1
log-file2
EOF
my $compiler = "gcc";
my $verbose = 0;
GetOptions( "gcc" => sub { $compiler = "gcc" },
"clang" => sub { $compiler = "clang" },
"v" => sub { $verbose = 1 },
) || die $usage;
my $num_arg = $#ARGV + 1;
if ($num_arg != 2) {
die $usage;
}
my $log1 = $ARGV[0];
my $log2 = $ARGV[1];
# Hashes: relative filename -> compiler invocation
my %cmd1 = read_log_file($log1);
my %cmd2 = read_log_file($log2);
# Compare the log files
foreach my $file (keys %cmd1) {
if (! $cmd2{$file}) {
print "*** $file missing in $log2\n";
} else {
compare_invocations($file, $cmd1{$file }, $cmd2{$file});
}
}
foreach my $file (keys %cmd2) {
if (! $cmd1{$file}) {
print "*** $file missing in $log1\n";
}
}
exit 0;
# Compare two lines |c1| and |c2| which are compiler invocations for |file|.
# Basically, we look at a compiler invocation as a sequence of blank-separated
# options.
sub compare_invocations {
my ($file, $c1, $c2) = @_;
my ($found1, $found2);
# print "COMPARE $file\n";
# Remove stuff that has embedded spaces
# Remove: `test -f 'whatever.c' || echo './'`
$c1 =~ s|(`[^`]*`)||;
$found1 = $1;
$c2 =~ s|(`[^`]*`)||;
$found2 = $1;
if ($found1 && $found2) {
die if ($found1 ne $found2);
}
# Remove: -o whatever
$c1 =~ s|-o[ ][ ]*([^ ][^ ]*)||;
$found1 = $1;
$c2 =~ s|-o[ ][ ]*([^ ][^ ]*)||;
$found2 = $1;
if ($found1 && $found2) {
die if ($found1 ne $found2);
}
# The remaining lines are considered to be blank-separated options and file
# names. They should be identical in both invocations (but in any order).
my %o1 = ();
my %o2 = ();
foreach my $k (split /\s+/,$c1) {
$o1{$k} = 1;
}
foreach my $k (split /\s+/,$c2) {
$o2{$k} = 1;
}
# foreach my $zz (keys %o1) {
# print "$zz\n";
# }
foreach my $k (keys %o1) {
if (! $o2{$k}) {
print "*** '$k' is missing in compilation of '$file' in $log2\n";
}
}
foreach my $k (keys %o2) {
if (! $o1{$k}) {
print "*** '$k' is missing in compilation of '$file' in $log1\n";
}
}
}
# Read a compiler log file.
# Return hash: relative (to build root) file name -> compiler invocation
sub read_log_file
{
my ($log) = @_;
my $dir = "";
my $root = "";
my %cmd = ();
print "...reading $log\n" if ($verbose);
open(LOG, "$log") || die "cannot open $log\n";
while (my $line = <LOG>) {
chomp $line;
if ($line =~ /^make/) {
if ($line =~ /Entering directory/) {
$dir = $line;
$dir =~ s/^.*`//;
$dir =~ s/'.*//;
if ($root eq "") {
$root = $dir;
# Append a slash if not present
$root = "$root/" if (! ($root =~ /\/$/));
print "...build root is $root\n" if ($verbose);
}
# print "DIR = $dir\n";
next;
}
}
if ($line =~ /^\s*[^\s]*$compiler\s/) {
# If line ends in \ read continuation line.
while ($line =~ /\\$/) {
my $next = <LOG>;
chomp($next);
$line =~ s/\\$//;
$line .= $next;
}
my $file = extract_file($line);
$file = "$dir/$file"; # make absolute
$file =~ s/$root//; # remove build root
# print "FILE $file\n";
$cmd{"$file"} = $line;
}
}
close(LOG);
my $num_invocations = int(keys %cmd);
if ($num_invocations == 0) {
print "*** File $log does not contain any compiler invocations\n";
} else {
print "...found $num_invocations invocations\n" if ($verbose);
}
return %cmd;
}
# Extract a file name from the command line. Assume there is a -o filename
# present. If not, issue a warning.
#
sub extract_file {
my($line) = @_;
# Look for -o executable
if ($line =~ /-o[ ][ ]*([^ ][^ ]*)/) {
return $1;
} else {
print "*** Could not extract file name from $line\n";
return "UNKNOWN";
}
}