+our $VERSION = '0.02';
+
+
+# CONSTANTS/VARIABLES
+
+# Regex to catch compiler commands.
+my $cc_regex = qr/
+ (?<!\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.
+my $cc_regex_full = qr/
+ (?:[a-z0-9_]+-(?:linux-|kfreebsd-)?gnu(?:eabi|eabihf)?-)?
+ $cc_regex
+ /x;
+# Regex to catch (GCC) compiler warnings.
+my $warning_regex = qr/^(.+?):(\d+):\d+: warning: (.+?) \[(.+?)\]$/;
+
+# List of source file extensions which require preprocessing.
+my @source_preprocess_compile_cpp = (
+ # C++
+ qw( cc cp cxx cpp CPP c++ C ),
+ # Objective-C++
+ qw( mm M ),
+);
+my @source_preprocess_compile = (
+ # C
+ qw( c ),
+ # Objective-C
+ qw( m ),
+ # (Objective-)C++
+ @source_preprocess_compile_cpp,
+ # Fortran
+ qw( F FOR fpp FPP FTN F90 F95 F03 F08 ),
+);
+my @source_preprocess_no_compile = (
+ # Assembly
+ qw( S sx ),
+);
+my @source_preprocess = (
+ @source_preprocess_compile,
+ @source_preprocess_no_compile,
+);
+# List of source file extensions which don't require preprocessing.
+my @source_no_preprocess_compile_cpp = (
+ # C++
+ qw( ii ),
+ # Objective-C++
+ qw( mii ),
+);
+my @source_no_preprocess_compile = (
+ # C
+ qw( i ),
+ # (Objective-)C++
+ @source_no_preprocess_compile_cpp,
+ # Objective-C
+ qw( mi ),
+ # Fortran
+ qw( f for ftn f90 f95 f03 f08 ),
+);
+my @source_no_preprocess_no_compile = (
+ # Assembly
+ qw( s ),
+);
+my @source_no_preprocess = (
+ @source_no_preprocess_compile,
+ @source_no_preprocess_no_compile,
+);
+# List of header file extensions which require preprocessing.
+my @header_preprocess = (
+ # C, C++, Objective-C, Objective-C++
+ qw( h ),
+ # C++
+ qw( hh H hp hxx hpp HPP h++ tcc ),
+);
+
+# Hashes for fast extensions lookup to check if a file falls in one of these
+# categories.
+my %extensions_no_preprocess = map { $_ => 1 } (
+ @source_no_preprocess,
+);
+my %extensions_preprocess = map { $_ => 1 } (
+ @header_preprocess,
+ @source_preprocess,
+);
+my %extensions_compile_link = map { $_ => 1 } (
+ @source_preprocess,
+ @source_no_preprocess,
+);
+my %extensions_compile = map { $_ => 1 } (
+ @source_preprocess_compile,
+ @source_no_preprocess_compile,
+);
+my %extensions_no_compile = map { $_ => 1 } (
+ @source_preprocess_no_compile,
+ @source_no_preprocess_no_compile,
+);
+my %extensions_compile_cpp = map { $_ => 1 } (
+ @source_preprocess_compile_cpp,
+ @source_no_preprocess_compile_cpp,
+);
+my %extension = map { $_ => 1 } (
+ @source_no_preprocess,
+ @header_preprocess,
+ @source_preprocess,
+);
+
+# Regexp to match file extensions.
+my $file_extension_regex = qr/
+ \s
+ \S+ # Filename without extension.
+ \.
+ ([^\/\\.,;:\s]+)# File extension.
+ (?=\s|\\) # At end of word. Can't use \b because some files have non
+ # word characters at the end and because \b matches double
+ # extensions (like .cpp.o). Works always as all lines are
+ # terminated with "\n".
+ /x;
+
+# Expected (hardening) flags. All flags are used as regexps.
+my @def_cflags = (
+ '-g',
+ '-O(?:2|3)',
+);
+my @def_cflags_format = (
+ '-Wformat',
+ '-Werror=format-security', # implies -Wformat-security
+);
+my @def_cflags_fortify = (
+ # fortify needs at least -O1, but -O2 is recommended anyway
+);
+my @def_cflags_stack = (
+ '-fstack-protector',
+ '--param=ssp-buffer-size=4',
+);
+my @def_cflags_pie = (
+ '-fPIE',
+);
+my @def_cxxflags = (
+ @def_cflags,
+);
+# @def_cxxflags_* is the same as @def_cflags_*.
+my @def_cppflags = ();
+my @def_cppflags_fortify = (
+ '-D_FORTIFY_SOURCE=2', # must be first, see cppflags_fortify_broken()
+);
+my @def_cppflags_fortify_bad = (
+ # These flags may overwrite -D_FORTIFY_SOURCE=2.
+ '-D_FORTIFY_SOURCE=0',
+ '-D_FORTIFY_SOURCE=1',
+);
+my @def_ldflags = ();
+my @def_ldflags_relro = (
+ '-Wl,(?:-z,)?relro',
+);
+my @def_ldflags_bindnow = (
+ '-Wl,(?:-z,)?now',
+);
+my @def_ldflags_pie = (
+ '-fPIE',
+ '-pie',
+);
+my @def_ldflags_pic = (
+ '-fPIC',
+ '-fpic',
+ '-shared',
+);
+# References to all flags checked by the flag checker.
+my @flag_refs = (
+ \@def_cflags,
+ \@def_cflags_format,
+ \@def_cflags_fortify,
+ \@def_cflags_stack,
+ \@def_cflags_pie,
+ \@def_cxxflags,
+ \@def_cppflags,
+ \@def_cppflags_fortify,
+ \@def_ldflags,
+ \@def_ldflags_relro,
+ \@def_ldflags_bindnow,
+ \@def_ldflags_pie,
+);
+# References to all used flags.
+my @flag_refs_all = (
+ @flag_refs,
+ \@def_cppflags_fortify_bad,
+ \@def_ldflags_pic,
+);
+# Renaming rules for the output so the regex parts are not visible. Also
+# stores string values of flag regexps above, see compile_flag_regexp().
+my %flag_renames = (
+ '-O(?:2|3)' => '-O2',
+ '-Wl,(?:-z,)?relro' => '-Wl,-z,relro',
+ '-Wl,(?:-z,)?now' => '-Wl,-z,now',
+);
+
+my %exit_code = (
+ no_compiler_commands => 1 << 0,
+ # used by POD::Usage => 1 << 1,
+ non_verbose_build => 1 << 2,
+ flags_missing => 1 << 3,
+ hardening_wrapper => 1 << 4,
+ 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 = (
+ preprocess => 0,
+ preprocess_missing => 0,
+ compile => 0,
+ compile_missing => 0,
+ compile_cpp => 0,
+ compile_cpp_missing => 0,
+ link => 0,
+ link_missing => 0,
+ commands => 0,
+ commands_nonverbose => 0,
+);
+
+# Use colored (ANSI) output?
+my $option_color;