Manual: C23 is now officially released
[valgrind.git] / auxprogs / compare-build-logs
blob704552b00dc6cdd8f9a1e54723f326a4eebe700a
1 #!/usr/bin/env perl
3 # Lame script to compare two build logs.
5 # The script intercepts directory changes and compiler invocations and
6 # compares the compiler invocations for equality. Equality is defined
7 # as "same options in both invocations ignoring order". So we only test
8 # a necessary condition.
10 # Both builds must be configured with the same --prefix. Otherwise,
11 # the value of -DVG_LIBDIR= will differ. They also need to use the same
12 # compiler.
14 use Getopt::Long;
15 use strict;
16 use warnings;
18 my $prog_name = "compare-build-logs";
20 my $usage=<<EOF;
21 USAGE
23 $prog_name log1 log2
25 [--gcc] intercept GCC invocations (this is default)
27 [--clang] intercept clang invocations
29 [-v] verbose mode
31 log-file1
33 log-file2
34 EOF
36 my $compiler = "gcc";
37 my $verbose = 0;
39 GetOptions( "gcc" => sub { $compiler = "gcc" },
40 "clang" => sub { $compiler = "clang" },
41 "v" => sub { $verbose = 1 },
42 ) || die $usage;
44 my $num_arg = $#ARGV + 1;
46 if ($num_arg != 2) {
47 die $usage;
50 my $log1 = $ARGV[0];
51 my $log2 = $ARGV[1];
53 # Hashes: relative filename -> compiler invocation
54 my %cmd1 = read_log_file($log1);
55 my %cmd2 = read_log_file($log2);
57 # Compare the log files
59 foreach my $file (keys %cmd1) {
60 if (! $cmd2{$file}) {
61 print "*** $file missing in $log2\n";
62 } else {
63 compare_invocations($file, $cmd1{$file }, $cmd2{$file});
66 foreach my $file (keys %cmd2) {
67 if (! $cmd1{$file}) {
68 print "*** $file missing in $log1\n";
72 exit 0;
74 # Compare two lines |c1| and |c2| which are compiler invocations for |file|.
75 # Basically, we look at a compiler invocation as a sequence of blank-separated
76 # options.
77 sub compare_invocations {
78 my ($file, $c1, $c2) = @_;
79 my ($found1, $found2);
80 # print "COMPARE $file\n";
82 # Remove stuff that has embedded spaces
84 # Remove: `test -f 'whatever.c' || echo './'`
85 $c1 =~ s|(`[^`]*`)||;
86 $found1 = $1;
87 $c2 =~ s|(`[^`]*`)||;
88 $found2 = $1;
89 if ($found1 && $found2) {
90 die if ($found1 ne $found2);
93 # Remove: -o whatever
94 $c1 =~ s|-o[ ][ ]*([^ ][^ ]*)||;
95 $found1 = $1;
96 $c2 =~ s|-o[ ][ ]*([^ ][^ ]*)||;
97 $found2 = $1;
98 if ($found1 && $found2) {
99 die if ($found1 ne $found2);
102 # The remaining lines are considered to be blank-separated options and file
103 # names. They should be identical in both invocations (but in any order).
104 my %o1 = ();
105 my %o2 = ();
106 foreach my $k (split /\s+/,$c1) {
107 $o1{$k} = 1;
109 foreach my $k (split /\s+/,$c2) {
110 $o2{$k} = 1;
112 # foreach my $zz (keys %o1) {
113 # print "$zz\n";
115 foreach my $k (keys %o1) {
116 if (! $o2{$k}) {
117 print "*** '$k' is missing in compilation of '$file' in $log2\n";
120 foreach my $k (keys %o2) {
121 if (! $o1{$k}) {
122 print "*** '$k' is missing in compilation of '$file' in $log1\n";
127 # Read a compiler log file.
128 # Return hash: relative (to build root) file name -> compiler invocation
129 sub read_log_file
131 my ($log) = @_;
132 my $dir = "";
133 my $root = "";
134 my %cmd = ();
136 print "...reading $log\n" if ($verbose);
138 open(LOG, "$log") || die "cannot open $log\n";
139 while (my $line = <LOG>) {
140 chomp $line;
141 if ($line =~ /^make/) {
142 if ($line =~ /Entering directory/) {
143 $dir = $line;
144 $dir =~ s/^.*`//;
145 $dir =~ s/'.*//;
146 if ($root eq "") {
147 $root = $dir;
148 # Append a slash if not present
149 $root = "$root/" if (! ($root =~ /\/$/));
150 print "...build root is $root\n" if ($verbose);
152 # print "DIR = $dir\n";
153 next;
156 if ($line =~ /^\s*[^\s]*$compiler\s/) {
157 # If line ends in \ read continuation line.
158 while ($line =~ /\\$/) {
159 my $next = <LOG>;
160 chomp($next);
161 $line =~ s/\\$//;
162 $line .= $next;
165 my $file = extract_file($line);
166 $file = "$dir/$file"; # make absolute
167 $file =~ s/$root//; # remove build root
168 # print "FILE $file\n";
169 $cmd{"$file"} = $line;
172 close(LOG);
174 my $num_invocations = int(keys %cmd);
176 if ($num_invocations == 0) {
177 print "*** File $log does not contain any compiler invocations\n";
178 } else {
179 print "...found $num_invocations invocations\n" if ($verbose);
181 return %cmd;
184 # Extract a file name from the command line. Assume there is a -o filename
185 # present. If not, issue a warning.
187 sub extract_file {
188 my($line) = @_;
189 # Look for -o executable
190 if ($line =~ /-o[ ][ ]*([^ ][^ ]*)/) {
191 return $1;
192 } else {
193 print "*** Could not extract file name from $line\n";
194 return "UNKNOWN";