#! /usr/bin/perl # Post-processor for compiler output to filter out warnings matched in # support-files/compiler_warnings.supp. This makes it easier to check # that no new warnings are introduced without needing to submit a build # for Buildbot. # # Use by setting CC="ccfilter gcc" CXX="ccfilter gcc" before ./configure. # # When testing from command line, you can run it as # perl ccfilter cat logfile > /dev/null # to see the errors that are not filtered # # By default, just filters the output for suppressed warnings. If the # FAILONWARNING environment variable is set, then instead will fail the # compile on encountering a non-suppressed warnings. use strict; use warnings; my $suppressions; my $filter_stderr= $ARGV[0] ne "cat"; open STDOUT_COPY, ">&STDOUT" or die "Failed to dup stdout: $!]n"; my $pid= open(PIPE, '-|'); if (!defined($pid)) { die "Error: Cannot fork(): $!\n"; } elsif (!$pid) { # Child. # actually want to send the STDERR to the parent, not the STDOUT. # So shuffle things around a bit. if ($filter_stderr) { open STDERR, ">&STDOUT" or die "Child: Failed to dup pipe to parent: $!\n"; open STDOUT, ">&STDOUT_COPY" or die "Child: Failed to dup parent stdout: $!\n"; close STDOUT_COPY; } exec { $ARGV[0] } @ARGV; die "Child: exec() failed: $!\n"; } else { # Parent. close STDOUT_COPY; my $cwd= qx(pwd); chomp($cwd); while () { my $line= $_; if (/^(.*?):([0-9]+):(?:[0-9]+:)? [Ww]arning: (.*)$/) { my ($file, $lineno, $msg)= ($1, $2, $3); $file= "$cwd/$file" if (length($file) > 0 && substr($file,0,1) ne "/"); next if check_if_suppressed($file, $lineno, $msg); die "$line\nGot warning, terminating.\n" if $ENV{FAILONWARNING}; print STDERR $line; next; } if ($filter_stderr) { print STDERR $line; } else { print STDOUT $line; } } close(PIPE); } exit 0; sub check_if_suppressed { my ($file, $lineno, $msg)= @_; load_suppressions() unless defined($suppressions); for my $s (@$suppressions) { my ($file_re, $msg_re, $start, $end)= @$s; if ($file =~ /$file_re/ && $msg =~ /$msg_re/ && (!defined($start) || $start <= $lineno) && (!defined($end) || $end >= $lineno)) { return 1; } } return undef; } sub load_suppressions { # First find the suppressions file, might be we need to move up to # the base directory. my $path = "support-files/compiler_warnings.supp"; my $exists; for (1..10) { $exists= -f $path; last if $exists; $path= '../'. $path; } die "Error: Could not find suppression file (out of source dir?).\n" unless $exists; $suppressions= []; open "F", "<", $path or die "Error: Could not read suppression file '$path': $!\n"; while () { # Skip comment and empty lines. next if /^\s*(\#.*)?$/; die "Invalid syntax in suppression file '$path', line $.:\n$_" unless /^\s*(.+?)\s*:\s*(.+?)\s*(?:[:]\s*([0-9]+)(?:-([0-9]+))?\s*)?$/; my ($file_re, $line_re, $start, $end)= ($1, $2, $3, $4); $end = $start if defined($start) && !defined($end); push @$suppressions, [$file_re, $line_re, $start, $end]; } }