+if ($option_all) {
+ $pie = 1;
+ $bindnow = 1;
+}
+
+# Final exit code.
+my $exit = 0;
+
+# Input lines, contain only the lines with compiler commands.
+my @input = ();
+
+my $continuation = 0;
+while (my $line = <>) {
+ # Ignore compiler warnings for now.
+ next if $line =~ /$warning_regex/;
+
+ # One line may contain multiple commands (";"). Treat each one as single
+ # line.
+ my @line = split /(?<!\\);/, $line;
+ foreach $line (@line) {
+ # Add newline, drop all other whitespace at the end of a line.
+ $line =~ s/\s+$//;
+ $line .= "\n";
+
+ if ($continuation) {
+ $continuation = 0;
+
+ # Join lines, but leave the "\" in place so it's clear where the
+ # original line break was.
+ chomp $input[-1];
+ $input[-1] .= ' ' . $line;
+
+ } else {
+ # Ignore lines with no compiler commands.
+ next if $line !~ /\b(cc|gcc|g\+\+|c\+\+)(\s|\\)/;
+
+ # Ignore false positives.
+ #
+ # `./configure` output.
+ if ($line =~ /^checking /) {
+ next;
+ }
+
+ push @input, $line;
+ }
+
+ # Line continuation, line ends with "\".
+ if ($line =~ /\\\s*$/) {
+ $continuation = 1;
+ }
+ }
+}
+
+if (scalar @input == 0) {
+ print "No compiler commands!\n";
+ $exit |= 1;
+ exit $exit;
+}
+
+# Check if additional hardening options were used. Used to ensure they are
+# used for the complete build.
+foreach my $line (@input) {
+ $pie = 1 if any_flags_used($line, @cflags_pie, @ldflags_pie);
+ $bindnow = 1 if any_flags_used($line, @ldflags_bindnow);
+}
+
+if ($pie) {
+ @cflags = (@cflags, @cflags_pie);
+ @ldflags = (@ldflags, @ldflags_pie);
+}
+if ($bindnow) {
+ @ldflags = (@ldflags, @ldflags_bindnow);
+}
+
+foreach my $line (@input) {
+ # Ignore false positives.
+ #
+ # ./configure summary.
+ next if $line =~ /^Compiler:\s+(cc|gcc|g\+\+|c\+\+)$/;
+
+ # Is this a compiler or linker command?
+ my $compiler = 1;
+ my $linker = 0;
+
+ # Linker commands.
+ if ($line =~ m{\s-o # -o
+ [\s\\]*\s+ # possible line continuation
+ ([A-Za-z0-9_/.-]+/)? # path to file
+ [A-Za-z0-9_-]+ # binary name (no dots!)
+ ([0-9.]*\.so[0-9.]*[a-z]? # library (including version)
+ |\.la)?
+ (\s|\\|\$) # end of file name
+ }x
+ or $line =~ /^libtool: link: /
+ or $line =~ m{\s*/bin/bash .+?libtool\s+(.+?\s+)?--mode=(re)?link}) {
+ $compiler = 0;
+ $linker = 1;
+ }
+
+ # If there are source files then it's compiling/linking in one step and we
+ # must check both.
+ if ($line =~ /\.(c|cc|cpp)\b/) {
+ $compiler = 1;
+ }
+
+ # Check hardening flags.
+ my @missing;
+ if ($compiler and not all_flags_used($line, \@missing, @cflags)
+ # Libraries linked with -fPIC don't have to (and can't) be linked
+ # with -fPIE as well. It's no error if only PIE flags are missing.
+ and not pic_pie_conflict($line, $pie, \@missing, @cflags_pie)) {
+ error_flags('CFLAGS missing', \@missing, \%flag_renames, $line);
+ $exit |= 1 << 2;
+ }
+ if ($compiler and not all_flags_used($line, \@missing, @cppflags)) {
+ error_flags('CPPFLAGS missing', \@missing, \%flag_renames, $line);
+ $exit |= 1 << 2;
+ }
+ if ($linker and not all_flags_used($line, \@missing, @ldflags)
+ # Same here, -fPIC conflicts with -fPIE.
+ and not pic_pie_conflict($line, $pie, \@missing, @ldflags_pie)) {
+ error_flags('LDFLAGS missing', \@missing, \%flag_renames, $line);
+ $exit |= 1 << 2;
+ }
+}
+
+exit $exit;
+