]> ruderich.org/simon Gitweb - blhc/blhc.git/blobdiff - bin/blhc
Fix --ignore-flag with -fPIE.
[blhc/blhc.git] / bin / blhc
index 49640dd5eb379c70d1fce2d22c47751582a47be7..a51c860158608a12116c60a5d5113d182014dbb0 100755 (executable)
--- a/bin/blhc
+++ b/bin/blhc
@@ -24,15 +24,17 @@ use warnings;
 use Getopt::Long ();
 use Text::ParseWords ();
 
 use Getopt::Long ();
 use Text::ParseWords ();
 
-our $VERSION = '0.01';
+our $VERSION = '0.02';
 
 
 # CONSTANTS/VARIABLES
 
 # Regex to catch compiler commands.
 my $cc_regex = qr/
 
 
 # CONSTANTS/VARIABLES
 
 # Regex to catch compiler commands.
 my $cc_regex = qr/
-    (?<!\.)(?:cc|gcc|g\+\+|c\+\+)
-    (?:-[\d.]+)?
+    (?<!\s-)               # ignore options, e.g. "-c++" [sic!] (used by swig)
+    (?<!\.)                # ignore file names, e.g. "test.gcc"
+    (?:cc|gcc|g\+\+|c\+\+)
+    (?:-[\d.]+)?           # version suffix, e.g. "gcc-4.6"
     /x;
 # Full regex which matches the complete compiler name. Used in a few places to
 # prevent false negatives.
     /x;
 # Full regex which matches the complete compiler name. Used in a few places to
 # prevent false negatives.
@@ -41,7 +43,7 @@ my $cc_regex_full = qr/
     $cc_regex
     /x;
 # Regex to catch (GCC) compiler warnings.
     $cc_regex
     /x;
 # Regex to catch (GCC) compiler warnings.
-my $warning_regex = qr/^(.+?):([0-9]+):[0-9]+: warning: (.+?) \[(.+?)\]$/;
+my $warning_regex = qr/^(.+?):(\d+):\d+: warning: (.+?) \[(.+?)\]$/;
 
 # List of source file extensions which require preprocessing.
 my @source_preprocess_compile_cpp = (
 
 # List of source file extensions which require preprocessing.
 my @source_preprocess_compile_cpp = (
@@ -151,8 +153,7 @@ my @def_cflags = (
 );
 my @def_cflags_format = (
     '-Wformat',
 );
 my @def_cflags_format = (
     '-Wformat',
-    '-Wformat-security',
-    '-Werror=format-security',
+    '-Werror=format-security', # implies -Wformat-security
 );
 my @def_cflags_fortify = (
     # fortify needs at least -O1, but -O2 is recommended anyway
 );
 my @def_cflags_fortify = (
     # fortify needs at least -O1, but -O2 is recommended anyway
@@ -201,11 +202,11 @@ my @flag_refs = (
     \@def_ldflags,
     \@def_ldflags_relro,
     \@def_ldflags_bindnow,
     \@def_ldflags,
     \@def_ldflags_relro,
     \@def_ldflags_bindnow,
+    \@def_ldflags_pie,
 );
 # References to all used flags.
 my @flag_refs_all = (
     @flag_refs,
 );
 # References to all used flags.
 my @flag_refs_all = (
     @flag_refs,
-    \@def_ldflags_pie,
     \@def_ldflags_pic,
 );
 # Renaming rules for the output so the regex parts are not visible. Also
     \@def_ldflags_pic,
 );
 # Renaming rules for the output so the regex parts are not visible. Also
@@ -225,6 +226,14 @@ my %exit_code = (
     invalid_cmake        => 1 << 5,
 );
 
     invalid_cmake        => 1 << 5,
 );
 
+my %buildd_tag = (
+    no_compiler_commands => 'I-no-compiler-commands',
+    non_verbose_build    => 'W-compiler-flags-hidden',
+    flags_missing        => 'W-dpkg-buildflags-missing',
+    hardening_wrapper    => 'I-hardening-wrapper-used',
+    invalid_cmake        => 'I-invalid-cmake-used',
+);
+
 # Statistics of missing flags and non-verbose build commands. Used for
 # $option_buildd.
 my %statistics = (
 # Statistics of missing flags and non-verbose build commands. Used for
 # $option_buildd.
 my %statistics = (
@@ -255,14 +264,14 @@ sub error_flags {
         } @{$missing_flags_ref};
 
     my $flags = join ' ', @missing_flags;
         } @{$missing_flags_ref};
 
     my $flags = join ' ', @missing_flags;
-    printf "%s (%s)%s %s",
+    printf '%s (%s)%s %s',
            error_color($message, 'red'), $flags, error_color(':', 'yellow'),
            $line;
 }
 sub error_non_verbose_build {
     my ($line) = @_;
 
            error_color($message, 'red'), $flags, error_color(':', 'yellow'),
            $line;
 }
 sub error_non_verbose_build {
     my ($line) = @_;
 
-    printf "%s%s %s",
+    printf '%s%s %s',
            error_color('NONVERBOSE BUILD', 'red'),
            error_color(':', 'yellow'),
            $line;
            error_color('NONVERBOSE BUILD', 'red'),
            error_color(':', 'yellow'),
            $line;
@@ -341,10 +350,10 @@ sub pic_pie_conflict {
 sub is_non_verbose_build {
     my ($line, $next_line, $skip_ref) = @_;
 
 sub is_non_verbose_build {
     my ($line, $next_line, $skip_ref) = @_;
 
-    if (not ($line =~ /^checking if you want to see long compiling messages\.\.\. no/
+    if (not (index($line, 'checking if you want to see long compiling messages... no') == 0
                 or $line =~ /^\s*\[?(?:CC|CCLD|C\+\+|CXX|CXXLD|LD|LINK)\]?\s+(.+?)$/
                 or $line =~ /^\s*\[?(?:CC|CCLD|C\+\+|CXX|CXXLD|LD|LINK)\]?\s+(.+?)$/
-                or $line =~ /^\s*(?:C|c)ompiling\s+(.+?)(?:\.\.\.)?$/
-                or $line =~ /^\s*(?:B|b)uilding (?:program|shared library)\s+(.+?)$/
+                or $line =~ /^\s*[Cc]ompiling\s+(.+?)(?:\.\.\.)?$/
+                or $line =~ /^\s*[Bb]uilding (?:program|shared library)\s+(.+?)$/
                 or $line =~ /^\s*\[[\d ]+%\] Building (?:C|CXX) object (.+?)$/)) {
         return 0;
     }
                 or $line =~ /^\s*\[[\d ]+%\] Building (?:C|CXX) object (.+?)$/)) {
         return 0;
     }
@@ -354,7 +363,7 @@ sub is_non_verbose_build {
     # C++ compiler setting.
     return 0 if $line =~ /^\s*C\+\+.+?:\s+(?:yes|no)\s*$/;
     # "Compiling" with no file name.
     # C++ compiler setting.
     return 0 if $line =~ /^\s*C\+\+.+?:\s+(?:yes|no)\s*$/;
     # "Compiling" with no file name.
-    if ($line =~ /^\s*(?:C|c)ompiling\s+(.+?)(?:\.\.\.)?$/) {
+    if ($line =~ /^\s*[Cc]ompiling\s+(.+?)(?:\.\.\.)?$/) {
         # $file_extension_regex may need spaces around the filename.
         return 0 if not " $1 " =~ /$file_extension_regex/o;
     }
         # $file_extension_regex may need spaces around the filename.
         return 0 if not " $1 " =~ /$file_extension_regex/o;
     }
@@ -376,7 +385,7 @@ sub is_non_verbose_build {
         $file =~ m{/([^/\s]+)$};
         $file = $1;
 
         $file =~ m{/([^/\s]+)$};
         $file = $1;
 
-        if ($next_line =~ /\Q$file\E/ and $next_line =~ /$cc_regex/o) {
+        if (index($next_line, $file) != -1 and $next_line =~ /$cc_regex/o) {
             # We still have to skip the current line as it doesn't contain any
             # compiler commands.
             ${$skip_ref} = 1;
             # We still have to skip the current line as it doesn't contain any
             # compiler commands.
             ${$skip_ref} = 1;
@@ -426,6 +435,7 @@ my $option_help        = 0;
 my $option_version     = 0;
 my $option_pie         = 0;
 my $option_bindnow     = 0;
 my $option_version     = 0;
 my $option_pie         = 0;
 my $option_bindnow     = 0;
+my @option_ignore_arch = ();
 my @option_ignore_flag = ();
 my @option_ignore_line = ();
 my $option_all         = 0;
 my @option_ignore_flag = ();
 my @option_ignore_line = ();
 my $option_all         = 0;
@@ -440,14 +450,14 @@ if (not Getopt::Long::GetOptions(
             'bindnow'       => \$option_bindnow,
             'all'           => \$option_all,
             # Ignore.
             'bindnow'       => \$option_bindnow,
             'all'           => \$option_all,
             # Ignore.
+            'ignore-arch=s' => \@option_ignore_arch,
             'ignore-flag=s' => \@option_ignore_flag,
             'ignore-line=s' => \@option_ignore_line,
             # Misc.
             'color'         => \$option_color,
             'arch=s'        => \$option_arch,
             'buildd'        => \$option_buildd,
             'ignore-flag=s' => \@option_ignore_flag,
             'ignore-line=s' => \@option_ignore_line,
             # Misc.
             'color'         => \$option_color,
             'arch=s'        => \$option_arch,
             'buildd'        => \$option_buildd,
-        )
-        or scalar @ARGV == 0) {
+        )) {
     require Pod::Usage;
     Pod::Usage::pod2usage(2);
 }
     require Pod::Usage;
     Pod::Usage::pod2usage(2);
 }
@@ -474,6 +484,12 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
     exit 0;
 }
 
     exit 0;
 }
 
+# Arguments missing.
+if (scalar @ARGV == 0) {
+    require Pod::Usage;
+    Pod::Usage::pod2usage(2);
+}
+
 # Don't load Term::ANSIColor in buildd mode because Term::ANSIColor is not
 # installed on Debian's buildds.
 if (not $option_buildd) {
 # Don't load Term::ANSIColor in buildd mode because Term::ANSIColor is not
 # installed on Debian's buildds.
 if (not $option_buildd) {
@@ -517,7 +533,7 @@ FILE:
 foreach my $file (@ARGV) {
     print "checking '$file'...\n" if scalar @ARGV > 1;
 
 foreach my $file (@ARGV) {
     print "checking '$file'...\n" if scalar @ARGV > 1;
 
-    open my $fh, '<', $file or die "$!: $file";
+    open my $fh, '<', $file or die $!;
 
     # Architecture of this file.
     my $arch = $option_arch;
 
     # Architecture of this file.
     my $arch = $option_arch;
@@ -531,15 +547,25 @@ foreach my $file (@ARGV) {
     my $harden_pie     = $option_pie;     # defaults to 0
 
     while (my $line = <$fh>) {
     my $harden_pie     = $option_pie;     # defaults to 0
 
     while (my $line = <$fh>) {
+        # Detect architecture automatically unless overridden. For buildd logs
+        # only, doesn't use the dpkg-buildpackage header. Necessary to ignore
+        # build logs which aren't built (wrong architecture, build error,
+        # etc.).
+        if (not $arch
+                and $line =~ /^Architecture: (.+)$/) {
+            $arch = $1;
+        }
+
         # dpkg-buildflags only provides hardening flags since 1.16.1, don't
         # check for hardening flags in buildd mode if an older dpkg-dev is
         # used. Default flags (-g -O2) are still checked.
         #
         # Packages which were built before 1.16.1 but used their own hardening
         # flags are not checked.
         # dpkg-buildflags only provides hardening flags since 1.16.1, don't
         # check for hardening flags in buildd mode if an older dpkg-dev is
         # used. Default flags (-g -O2) are still checked.
         #
         # Packages which were built before 1.16.1 but used their own hardening
         # flags are not checked.
-        if ($option_buildd and $line =~ /^Toolchain package versions: /) {
+        if ($option_buildd
+                and index($line, 'Toolchain package versions: ') == 0) {
             require Dpkg::Version;
             require Dpkg::Version;
-            if ($line !~ /\bdpkg-dev_(\S+)/
+            if (not $line =~ /\bdpkg-dev_(\S+)/
                     or Dpkg::Version::version_compare($1, '1.16.1') < 0) {
                 $harden_format  = 0;
                 $harden_fortify = 0;
                     or Dpkg::Version::version_compare($1, '1.16.1') < 0) {
                 $harden_format  = 0;
                 $harden_fortify = 0;
@@ -556,24 +582,25 @@ foreach my $file (@ARGV) {
         # enabled, even though they may be not correctly set and are missing
         # when build with later CMake versions. Thanks to Aron Xu for letting
         # me know.
         # enabled, even though they may be not correctly set and are missing
         # when build with later CMake versions. Thanks to Aron Xu for letting
         # me know.
-        if ($line =~ /^Package versions: /
+        if (index($line, 'Package versions: ') == 0
                 and $line =~ /\bcmake_(\S+)/
                 and ($1 eq '2.8.7-1' or $1 eq '2.8.7-2')) {
             if (not $option_buildd) {
                 error_invalid_cmake($1);
             } else {
                 and $line =~ /\bcmake_(\S+)/
                 and ($1 eq '2.8.7-1' or $1 eq '2.8.7-2')) {
             if (not $option_buildd) {
                 error_invalid_cmake($1);
             } else {
-                print "W-invalid-cmake-used $1\n";
+                print "$buildd_tag{invalid_cmake} $1\n";
             }
             $exit |= $exit_code{invalid_cmake};
         }
 
         # If hardening wrapper is used (wraps calls to gcc and adds hardening
         # flags automatically) we can't perform any checks, abort.
             }
             $exit |= $exit_code{invalid_cmake};
         }
 
         # If hardening wrapper is used (wraps calls to gcc and adds hardening
         # flags automatically) we can't perform any checks, abort.
-        if ($line =~ /^Build-Depends: .*\bhardening-wrapper\b/) {
+        if (index($line, 'Build-Depends: ') == 0
+                and $line =~ /\bhardening-wrapper\b/) {
             if (not $option_buildd) {
                 error_hardening_wrapper();
             } else {
             if (not $option_buildd) {
                 error_hardening_wrapper();
             } else {
-                print "I-hardening-wrapper-used\n";
+                print "$buildd_tag{hardening_wrapper}\n";
             }
             $exit |= $exit_code{hardening_wrapper};
             next FILE;
             }
             $exit |= $exit_code{hardening_wrapper};
             next FILE;
@@ -581,7 +608,7 @@ foreach my $file (@ARGV) {
 
         # We skip over unimportant lines at the beginning of the log to
         # prevent false positives.
 
         # We skip over unimportant lines at the beginning of the log to
         # prevent false positives.
-        last if $line =~ /^dpkg-buildpackage:/;
+        last if index($line, 'dpkg-buildpackage: ') == 0;
     }
 
     # Input lines, contain only the lines with compiler commands.
     }
 
     # Input lines, contain only the lines with compiler commands.
@@ -604,7 +631,7 @@ foreach my $file (@ARGV) {
         # Ignore compiler warnings for now.
         next if $line =~ /$warning_regex/o;
 
         # Ignore compiler warnings for now.
         next if $line =~ /$warning_regex/o;
 
-        if (not $option_buildd and $line =~ /\033/) { # esc
+        if (not $option_buildd and index($line, "\033") != -1) { # esc
             # Remove all ANSI color sequences which are sometimes used in
             # non-verbose builds.
             $line = Term::ANSIColor::colorstrip($line);
             # Remove all ANSI color sequences which are sometimes used in
             # non-verbose builds.
             $line = Term::ANSIColor::colorstrip($line);
@@ -621,7 +648,7 @@ foreach my $file (@ARGV) {
 
         # One line may contain multiple commands (";"). Treat each one as
         # single line. parse_line() is slow, only use it when necessary.
 
         # One line may contain multiple commands (";"). Treat each one as
         # single line. parse_line() is slow, only use it when necessary.
-        my @line = (not $line =~ /;/)
+        my @line = (index($line, ';') == -1)
                  ? ($line)
                  : map {
                        # Ensure newline at the line end - necessary for
                  ? ($line)
                  : map {
                        # Ensure newline at the line end - necessary for
@@ -629,7 +656,7 @@ foreach my $file (@ARGV) {
                        $_ =~ s/\s+$//;
                        $_ .= "\n";
                    } Text::ParseWords::parse_line(';', 1, $line);
                        $_ =~ s/\s+$//;
                        $_ .= "\n";
                    } Text::ParseWords::parse_line(';', 1, $line);
-        foreach $line (@line) {
+        foreach my $line (@line) {
             if ($continuation) {
                 $continuation = 0;
 
             if ($continuation) {
                 $continuation = 0;
 
@@ -639,7 +666,7 @@ foreach my $file (@ARGV) {
                 $complete_line .= ' ' . $line;
             }
             # Line continuation, line ends with "\".
                 $complete_line .= ' ' . $line;
             }
             # Line continuation, line ends with "\".
-            if ($line =~ /\\\s*$/) {
+            if ($line =~ /\\$/) {
                 $continuation = 1;
                 # Start line continuation.
                 if (not defined $complete_line) {
                 $continuation = 1;
                 # Start line continuation.
                 if (not defined $complete_line) {
@@ -668,9 +695,9 @@ foreach my $file (@ARGV) {
             #
             # `./configure` output.
             next if not $non_verbose
             #
             # `./configure` output.
             next if not $non_verbose
-                    and $line =~ /^(?:checking|(?:C|c)onfigure:) /;
+                    and $line =~ /^(?:checking|[Cc]onfigure:) /;
             next if $line =~ /^\s*(?:Host\s+)?(?:C(?:\+\+)?\s+)?
             next if $line =~ /^\s*(?:Host\s+)?(?:C(?:\+\+)?\s+)?
-                                (?:C|c)ompiler[\s.]*:?\s+
+                                [Cc]ompiler[\s.]*:?\s+
                                 /xo;
             next if $line =~ /^\s*(?:- )?(?:HOST_)?(?:CC|CXX)\s*=\s*$cc_regex_full\s*$/o;
 
                                 /xo;
             next if $line =~ /^\s*(?:- )?(?:HOST_)?(?:CC|CXX)\s*=\s*$cc_regex_full\s*$/o;
 
@@ -683,13 +710,23 @@ foreach my $file (@ARGV) {
         }
     }
 
         }
     }
 
-    close $fh;
+    close $fh or die $!;
+
+    # Ignore arch if requested.
+    if (scalar @option_ignore_arch > 0 and $arch) {
+        foreach my $ignore (@option_ignore_arch) {
+            if ($arch eq $ignore) {
+                print "ignoring architecture '$arch'\n";
+                next FILE;
+            }
+        }
+    }
 
     if (scalar @input == 0) {
         if (not $option_buildd) {
             print "No compiler commands!\n";
         } else {
 
     if (scalar @input == 0) {
         if (not $option_buildd) {
             print "No compiler commands!\n";
         } else {
-            print "W-no-compiler-commands\n";
+            print "$buildd_tag{no_compiler_commands}\n";
         }
         $exit |= $exit_code{no_compiler_commands};
         next FILE;
         }
         $exit |= $exit_code{no_compiler_commands};
         next FILE;
@@ -711,10 +748,10 @@ foreach my $file (@ARGV) {
         my ($abi, $os, $cpu) = Dpkg::Arch::debarch_to_debtriplet($arch);
 
         # Disable unsupported hardening options.
         my ($abi, $os, $cpu) = Dpkg::Arch::debarch_to_debtriplet($arch);
 
         # Disable unsupported hardening options.
-        if ($cpu =~ /^(ia64|alpha|mips|mipsel|hppa)$/ or $arch eq 'arm') {
+        if ($cpu =~ /^(?:ia64|alpha|mips|mipsel|hppa)$/ or $arch eq 'arm') {
             $harden_stack = 0;
         }
             $harden_stack = 0;
         }
-        if ($cpu =~ /^(ia64|hppa|avr32)$/) {
+        if ($cpu =~ /^(?:ia64|hppa|avr32)$/) {
             $harden_relro   = 0;
             $harden_bindnow = 0;
         }
             $harden_relro   = 0;
             $harden_bindnow = 0;
         }
@@ -865,7 +902,7 @@ LINE:
                 # are missing.
                 and not pic_pie_conflict($line, $harden_pie, \@missing, @def_cflags_pie)
                 # Assume dpkg-buildflags returns the correct flags.
                 # are missing.
                 and not pic_pie_conflict($line, $harden_pie, \@missing, @def_cflags_pie)
                 # Assume dpkg-buildflags returns the correct flags.
-                and not $line =~ /`dpkg-buildflags --get CFLAGS`/) {
+                and index($line, '`dpkg-buildflags --get CFLAGS`') == -1) {
             if (not $option_buildd) {
                 error_flags('CFLAGS missing', \@missing, \%flag_renames, $input[$i]);
             } else {
             if (not $option_buildd) {
                 error_flags('CFLAGS missing', \@missing, \%flag_renames, $input[$i]);
             } else {
@@ -878,7 +915,7 @@ LINE:
                 # are missing.
                 and not pic_pie_conflict($line, $harden_pie, \@missing, @def_cflags_pie)
                 # Assume dpkg-buildflags returns the correct flags.
                 # are missing.
                 and not pic_pie_conflict($line, $harden_pie, \@missing, @def_cflags_pie)
                 # Assume dpkg-buildflags returns the correct flags.
-                and not $line =~ /`dpkg-buildflags --get CXXFLAGS`/) {
+                and index($line, '`dpkg-buildflags --get CXXFLAGS`') == -1) {
             if (not $option_buildd) {
                 error_flags('CXXFLAGS missing', \@missing, \%flag_renames, $input[$i]);
             } else {
             if (not $option_buildd) {
                 error_flags('CXXFLAGS missing', \@missing, \%flag_renames, $input[$i]);
             } else {
@@ -888,7 +925,7 @@ LINE:
         }
         if ($preprocess and not all_flags_used($line, \@missing, @cppflags)
                 # Assume dpkg-buildflags returns the correct flags.
         }
         if ($preprocess and not all_flags_used($line, \@missing, @cppflags)
                 # Assume dpkg-buildflags returns the correct flags.
-                and not $line =~ /`dpkg-buildflags --get CPPFLAGS`/) {
+                and index($line, '`dpkg-buildflags --get CPPFLAGS`') == -1) {
             if (not $option_buildd) {
                 error_flags('CPPFLAGS missing', \@missing, \%flag_renames, $input[$i]);
             } else {
             if (not $option_buildd) {
                 error_flags('CPPFLAGS missing', \@missing, \%flag_renames, $input[$i]);
             } else {
@@ -900,7 +937,7 @@ LINE:
                 # Same here, -fPIC conflicts with -fPIE.
                 and not pic_pie_conflict($line, $harden_pie, \@missing, @def_ldflags_pie)
                 # Assume dpkg-buildflags returns the correct flags.
                 # Same here, -fPIC conflicts with -fPIE.
                 and not pic_pie_conflict($line, $harden_pie, \@missing, @def_ldflags_pie)
                 # Assume dpkg-buildflags returns the correct flags.
-                and not $line =~ /`dpkg-buildflags --get LDFLAGS`/) {
+                and index($line, '`dpkg-buildflags --get LDFLAGS`') == -1) {
             if (not $option_buildd) {
                 error_flags('LDFLAGS missing', \@missing, \%flag_renames, $input[$i]);
             } else {
             if (not $option_buildd) {
                 error_flags('LDFLAGS missing', \@missing, \%flag_renames, $input[$i]);
             } else {
@@ -916,32 +953,32 @@ if ($option_buildd) {
     my @warning;
 
     if ($statistics{preprocess_missing}) {
     my @warning;
 
     if ($statistics{preprocess_missing}) {
-        push @warning, sprintf "CPPFLAGS %d (of %d)",
+        push @warning, sprintf 'CPPFLAGS %d (of %d)',
                                $statistics{preprocess_missing},
                                $statistics{preprocess};
     }
     if ($statistics{compile_missing}) {
                                $statistics{preprocess_missing},
                                $statistics{preprocess};
     }
     if ($statistics{compile_missing}) {
-        push @warning, sprintf "CFLAGS %d (of %d)",
+        push @warning, sprintf 'CFLAGS %d (of %d)',
                                $statistics{compile_missing},
                                $statistics{compile};
     }
     if ($statistics{compile_cpp_missing}) {
                                $statistics{compile_missing},
                                $statistics{compile};
     }
     if ($statistics{compile_cpp_missing}) {
-        push @warning, sprintf "CXXFLAGS %d (of %d)",
+        push @warning, sprintf 'CXXFLAGS %d (of %d)',
                                $statistics{compile_cpp_missing},
                                $statistics{compile_cpp};
     }
     if ($statistics{link_missing}) {
                                $statistics{compile_cpp_missing},
                                $statistics{compile_cpp};
     }
     if ($statistics{link_missing}) {
-        push @warning, sprintf "LDFLAGS %d (of %d)",
+        push @warning, sprintf 'LDFLAGS %d (of %d)',
                                $statistics{link_missing},
                                $statistics{link};
     }
     if (scalar @warning) {
         local $" = ', '; # array join string
                                $statistics{link_missing},
                                $statistics{link};
     }
     if (scalar @warning) {
         local $" = ', '; # array join string
-        print "W-dpkg-buildflags-missing @warning missing\n";
+        print "$buildd_tag{flags_missing} @warning missing\n";
     }
 
     if ($statistics{commands_nonverbose}) {
     }
 
     if ($statistics{commands_nonverbose}) {
-        printf "W-compiler-flags-hidden %d (of %d) hidden\n",
+        printf "$buildd_tag{non_verbose_build} %d (of %d) hidden\n",
                $statistics{commands_nonverbose},
                $statistics{commands},
     }
                $statistics{commands_nonverbose},
                $statistics{commands},
     }
@@ -996,17 +1033,17 @@ changes are in effect:
 
 =over 2
 
 
 =over 2
 
-=item
+=item *
 
 Print tags instead of normal warnings, see L</"BUILDD TAGS"> for a list of
 possible tags.
 
 
 Print tags instead of normal warnings, see L</"BUILDD TAGS"> for a list of
 possible tags.
 
-=item
+=item *
 
 Don't check hardening flags in old log files (if dpkg-dev << 1.16.1 is
 detected).
 
 
 Don't check hardening flags in old log files (if dpkg-dev << 1.16.1 is
 detected).
 
-=item
+=item *
 
 Don't require Term::ANSIColor.
 
 
 Don't require Term::ANSIColor.
 
@@ -1016,6 +1053,12 @@ Don't require Term::ANSIColor.
 
 Use colored (ANSI) output for warning messages.
 
 
 Use colored (ANSI) output for warning messages.
 
+=item B<--ignore-arch> I<arch>
+
+Ignore build logs from architectures matching I<arch>. I<arch> is a string.
+
+Used to prevent false positives. This option can be specified multiple times.
+
 =item B<--ignore-flag> I<flag>
 
 Don't print an error when the specific flag is missing in a compiler line.
 =item B<--ignore-flag> I<flag>
 
 Don't print an error when the specific flag is missing in a compiler line.
@@ -1086,17 +1129,13 @@ which is displayed.
 
 =over 2
 
 
 =over 2
 
-=item
-
-B<I-hardening-wrapper-used>
+=item B<I-hardening-wrapper-used>
 
 The package uses hardening-wrapper which intercepts calls to gcc and adds
 hardening flags. The build log doesn't contain any hardening flags and thus
 can't be checked by blhc.
 
 
 The package uses hardening-wrapper which intercepts calls to gcc and adds
 hardening flags. The build log doesn't contain any hardening flags and thus
 can't be checked by blhc.
 
-=item
-
-B<W-compiler-flags-hidden> (summary of hidden lines)
+=item B<W-compiler-flags-hidden> (summary of hidden lines)
 
 Build log contains lines which hide the real compiler flags. For example:
 
 
 Build log contains lines which hide the real compiler flags. For example:
 
@@ -1110,19 +1149,20 @@ F<debian/rules> fixes builds with hidden compiler flags. Sometimes C<.SILENT>
 in a F<Makefile> must be removed. And as last resort the F<Makefile> must be
 patched to remove the C<@>s hiding the real compiler commands.
 
 in a F<Makefile> must be removed. And as last resort the F<Makefile> must be
 patched to remove the C<@>s hiding the real compiler commands.
 
-=item
-
-B<W-dpkg-buildflags-missing> (summary of missing flags)
+=item B<W-dpkg-buildflags-missing> (summary of missing flags)
 
 CPPFLAGS, CFLAGS, CXXFLAGS, LDFLAGS missing.
 
 
 CPPFLAGS, CFLAGS, CXXFLAGS, LDFLAGS missing.
 
-=item
+=item B<I-invalid-cmake-used> (version)
 
 
-B<W-invalid-cmake-used> (version)
+By default CMake ignores CPPFLAGS thus missing those hardening flags. Debian
+patched CMake in versions 2.8.7-1 and 2.8.7-2 to respect CPPFLAGS, but this
+patch was rejected by upstream and later reverted in Debian. Thus those two
+versions show correct usage of CPPFLAGS even if the package doesn't correctly
+handle them (for example by passing them to CFLAGS). To prevent false
+negatives just blacklist those two versions.
 
 
-=item
-
-B<W-no-compiler-commands>
+=item B<I-no-compiler-commands>
 
 No compiler commands were detected. Either the log contains none or they were
 not correctly detected by blhc (please report the bug in this case).
 
 No compiler commands were detected. Either the log contains none or they were
 not correctly detected by blhc (please report the bug in this case).
@@ -1160,6 +1200,11 @@ Missing hardening flags.
 
 Hardening wrapper detected, no tests performed.
 
 
 Hardening wrapper detected, no tests performed.
 
+=item B<32>
+
+Invalid CMake version used. See B<I-invalid-cmake-used> under L</"BUILDD
+TAGS"> for a detailed explanation.
+
 =back
 
 =head1 AUTHOR
 =back
 
 =head1 AUTHOR