1f4a2713aSLionel Sambuc#!/usr/bin/env perl 2f4a2713aSLionel Sambuc# 3f4a2713aSLionel Sambuc# The LLVM Compiler Infrastructure 4f4a2713aSLionel Sambuc# 5f4a2713aSLionel Sambuc# This file is distributed under the University of Illinois Open Source 6f4a2713aSLionel Sambuc# License. See LICENSE.TXT for details. 7f4a2713aSLionel Sambuc# 8f4a2713aSLionel Sambuc##===----------------------------------------------------------------------===## 9f4a2713aSLionel Sambuc# 10f4a2713aSLionel Sambuc# A script designed to interpose between the build system and gcc. It invokes 11f4a2713aSLionel Sambuc# both gcc and the static analyzer. 12f4a2713aSLionel Sambuc# 13f4a2713aSLionel Sambuc##===----------------------------------------------------------------------===## 14f4a2713aSLionel Sambuc 15f4a2713aSLionel Sambucuse strict; 16f4a2713aSLionel Sambucuse warnings; 17f4a2713aSLionel Sambucuse FindBin; 18f4a2713aSLionel Sambucuse Cwd qw/ getcwd abs_path /; 19f4a2713aSLionel Sambucuse File::Temp qw/ tempfile /; 20f4a2713aSLionel Sambucuse File::Path qw / mkpath /; 21f4a2713aSLionel Sambucuse File::Basename; 22f4a2713aSLionel Sambucuse Text::ParseWords; 23f4a2713aSLionel Sambuc 24f4a2713aSLionel Sambuc##===----------------------------------------------------------------------===## 25f4a2713aSLionel Sambuc# Compiler command setup. 26f4a2713aSLionel Sambuc##===----------------------------------------------------------------------===## 27f4a2713aSLionel Sambuc 28*0a6a1f1dSLionel Sambuc# Search in the PATH if the compiler exists 29*0a6a1f1dSLionel Sambucsub SearchInPath { 30*0a6a1f1dSLionel Sambuc my $file = shift; 31*0a6a1f1dSLionel Sambuc foreach my $dir (split (':', $ENV{PATH})) { 32*0a6a1f1dSLionel Sambuc if (-x "$dir/$file") { 33*0a6a1f1dSLionel Sambuc return 1; 34*0a6a1f1dSLionel Sambuc } 35*0a6a1f1dSLionel Sambuc } 36*0a6a1f1dSLionel Sambuc return 0; 37*0a6a1f1dSLionel Sambuc} 38*0a6a1f1dSLionel Sambuc 39f4a2713aSLionel Sambucmy $Compiler; 40f4a2713aSLionel Sambucmy $Clang; 41f4a2713aSLionel Sambucmy $DefaultCCompiler; 42f4a2713aSLionel Sambucmy $DefaultCXXCompiler; 43*0a6a1f1dSLionel Sambucmy $IsCXX; 44*0a6a1f1dSLionel Sambuc 45*0a6a1f1dSLionel Sambuc# If on OSX, use xcrun to determine the SDK root. 46*0a6a1f1dSLionel Sambucmy $UseXCRUN = 0; 47f4a2713aSLionel Sambuc 48f4a2713aSLionel Sambucif (`uname -a` =~ m/Darwin/) { 49f4a2713aSLionel Sambuc $DefaultCCompiler = 'clang'; 50f4a2713aSLionel Sambuc $DefaultCXXCompiler = 'clang++'; 51*0a6a1f1dSLionel Sambuc # Older versions of OSX do not have xcrun to 52*0a6a1f1dSLionel Sambuc # query the SDK location. 53*0a6a1f1dSLionel Sambuc if (-x "/usr/bin/xcrun") { 54*0a6a1f1dSLionel Sambuc $UseXCRUN = 1; 55*0a6a1f1dSLionel Sambuc } 56f4a2713aSLionel Sambuc} else { 57f4a2713aSLionel Sambuc $DefaultCCompiler = 'gcc'; 58f4a2713aSLionel Sambuc $DefaultCXXCompiler = 'g++'; 59f4a2713aSLionel Sambuc} 60f4a2713aSLionel Sambuc 61f4a2713aSLionel Sambucif ($FindBin::Script =~ /c\+\+-analyzer/) { 62f4a2713aSLionel Sambuc $Compiler = $ENV{'CCC_CXX'}; 63*0a6a1f1dSLionel Sambuc if (!defined $Compiler || (! -x $Compiler && ! SearchInPath($Compiler))) { $Compiler = $DefaultCXXCompiler; } 64f4a2713aSLionel Sambuc 65f4a2713aSLionel Sambuc $Clang = $ENV{'CLANG_CXX'}; 66*0a6a1f1dSLionel Sambuc if (!defined $Clang || ! -x $Clang) { $Clang = 'clang++'; } 67*0a6a1f1dSLionel Sambuc 68*0a6a1f1dSLionel Sambuc $IsCXX = 1 69f4a2713aSLionel Sambuc} 70f4a2713aSLionel Sambucelse { 71f4a2713aSLionel Sambuc $Compiler = $ENV{'CCC_CC'}; 72*0a6a1f1dSLionel Sambuc if (!defined $Compiler || (! -x $Compiler && ! SearchInPath($Compiler))) { $Compiler = $DefaultCCompiler; } 73f4a2713aSLionel Sambuc 74f4a2713aSLionel Sambuc $Clang = $ENV{'CLANG'}; 75*0a6a1f1dSLionel Sambuc if (!defined $Clang || ! -x $Clang) { $Clang = 'clang'; } 76*0a6a1f1dSLionel Sambuc 77*0a6a1f1dSLionel Sambuc $IsCXX = 0 78f4a2713aSLionel Sambuc} 79f4a2713aSLionel Sambuc 80f4a2713aSLionel Sambuc##===----------------------------------------------------------------------===## 81f4a2713aSLionel Sambuc# Cleanup. 82f4a2713aSLionel Sambuc##===----------------------------------------------------------------------===## 83f4a2713aSLionel Sambuc 84f4a2713aSLionel Sambucmy $ReportFailures = $ENV{'CCC_REPORT_FAILURES'}; 85f4a2713aSLionel Sambucif (!defined $ReportFailures) { $ReportFailures = 1; } 86f4a2713aSLionel Sambuc 87f4a2713aSLionel Sambucmy $CleanupFile; 88f4a2713aSLionel Sambucmy $ResultFile; 89f4a2713aSLionel Sambuc 90f4a2713aSLionel Sambuc# Remove any stale files at exit. 91f4a2713aSLionel SambucEND { 92f4a2713aSLionel Sambuc if (defined $ResultFile && -z $ResultFile) { 93*0a6a1f1dSLionel Sambuc unlink($ResultFile); 94f4a2713aSLionel Sambuc } 95f4a2713aSLionel Sambuc if (defined $CleanupFile) { 96*0a6a1f1dSLionel Sambuc unlink($CleanupFile); 97f4a2713aSLionel Sambuc } 98f4a2713aSLionel Sambuc} 99f4a2713aSLionel Sambuc 100f4a2713aSLionel Sambuc##----------------------------------------------------------------------------## 101f4a2713aSLionel Sambuc# Process Clang Crashes. 102f4a2713aSLionel Sambuc##----------------------------------------------------------------------------## 103f4a2713aSLionel Sambuc 104f4a2713aSLionel Sambucsub GetPPExt { 105f4a2713aSLionel Sambuc my $Lang = shift; 106f4a2713aSLionel Sambuc if ($Lang =~ /objective-c\+\+/) { return ".mii" }; 107f4a2713aSLionel Sambuc if ($Lang =~ /objective-c/) { return ".mi"; } 108f4a2713aSLionel Sambuc if ($Lang =~ /c\+\+/) { return ".ii"; } 109f4a2713aSLionel Sambuc return ".i"; 110f4a2713aSLionel Sambuc} 111f4a2713aSLionel Sambuc 112f4a2713aSLionel Sambuc# Set this to 1 if we want to include 'parser rejects' files. 113f4a2713aSLionel Sambucmy $IncludeParserRejects = 0; 114f4a2713aSLionel Sambucmy $ParserRejects = "Parser Rejects"; 115f4a2713aSLionel Sambucmy $AttributeIgnored = "Attribute Ignored"; 116f4a2713aSLionel Sambucmy $OtherError = "Other Error"; 117f4a2713aSLionel Sambuc 118f4a2713aSLionel Sambucsub ProcessClangFailure { 119f4a2713aSLionel Sambuc my ($Clang, $Lang, $file, $Args, $HtmlDir, $ErrorType, $ofile) = @_; 120f4a2713aSLionel Sambuc my $Dir = "$HtmlDir/failures"; 121f4a2713aSLionel Sambuc mkpath $Dir; 122f4a2713aSLionel Sambuc 123f4a2713aSLionel Sambuc my $prefix = "clang_crash"; 124f4a2713aSLionel Sambuc if ($ErrorType eq $ParserRejects) { 125f4a2713aSLionel Sambuc $prefix = "clang_parser_rejects"; 126f4a2713aSLionel Sambuc } 127f4a2713aSLionel Sambuc elsif ($ErrorType eq $AttributeIgnored) { 128f4a2713aSLionel Sambuc $prefix = "clang_attribute_ignored"; 129f4a2713aSLionel Sambuc } 130f4a2713aSLionel Sambuc elsif ($ErrorType eq $OtherError) { 131f4a2713aSLionel Sambuc $prefix = "clang_other_error"; 132f4a2713aSLionel Sambuc } 133f4a2713aSLionel Sambuc 134f4a2713aSLionel Sambuc # Generate the preprocessed file with Clang. 135f4a2713aSLionel Sambuc my ($PPH, $PPFile) = tempfile( $prefix . "_XXXXXX", 136f4a2713aSLionel Sambuc SUFFIX => GetPPExt($Lang), 137f4a2713aSLionel Sambuc DIR => $Dir); 138f4a2713aSLionel Sambuc system $Clang, @$Args, "-E", "-o", $PPFile; 139f4a2713aSLionel Sambuc close ($PPH); 140f4a2713aSLionel Sambuc 141f4a2713aSLionel Sambuc # Create the info file. 142f4a2713aSLionel Sambuc open (OUT, ">", "$PPFile.info.txt") or die "Cannot open $PPFile.info.txt\n"; 143f4a2713aSLionel Sambuc print OUT abs_path($file), "\n"; 144f4a2713aSLionel Sambuc print OUT "$ErrorType\n"; 145f4a2713aSLionel Sambuc print OUT "@$Args\n"; 146f4a2713aSLionel Sambuc close OUT; 147f4a2713aSLionel Sambuc `uname -a >> $PPFile.info.txt 2>&1`; 148f4a2713aSLionel Sambuc `$Compiler -v >> $PPFile.info.txt 2>&1`; 149*0a6a1f1dSLionel Sambuc rename($ofile, "$PPFile.stderr.txt"); 150f4a2713aSLionel Sambuc return (basename $PPFile); 151f4a2713aSLionel Sambuc} 152f4a2713aSLionel Sambuc 153f4a2713aSLionel Sambuc##----------------------------------------------------------------------------## 154f4a2713aSLionel Sambuc# Running the analyzer. 155f4a2713aSLionel Sambuc##----------------------------------------------------------------------------## 156f4a2713aSLionel Sambuc 157f4a2713aSLionel Sambucsub GetCCArgs { 158f4a2713aSLionel Sambuc my $mode = shift; 159f4a2713aSLionel Sambuc my $Args = shift; 160f4a2713aSLionel Sambuc 161f4a2713aSLionel Sambuc pipe (FROM_CHILD, TO_PARENT); 162f4a2713aSLionel Sambuc my $pid = fork(); 163f4a2713aSLionel Sambuc if ($pid == 0) { 164f4a2713aSLionel Sambuc close FROM_CHILD; 165f4a2713aSLionel Sambuc open(STDOUT,">&", \*TO_PARENT); 166f4a2713aSLionel Sambuc open(STDERR,">&", \*TO_PARENT); 167f4a2713aSLionel Sambuc exec $Clang, "-###", $mode, @$Args; 168f4a2713aSLionel Sambuc } 169f4a2713aSLionel Sambuc close(TO_PARENT); 170f4a2713aSLionel Sambuc my $line; 171f4a2713aSLionel Sambuc while (<FROM_CHILD>) { 172*0a6a1f1dSLionel Sambuc next if (!/\s"?-cc1"?\s/); 173f4a2713aSLionel Sambuc $line = $_; 174f4a2713aSLionel Sambuc } 175f4a2713aSLionel Sambuc 176f4a2713aSLionel Sambuc waitpid($pid,0); 177f4a2713aSLionel Sambuc close(FROM_CHILD); 178f4a2713aSLionel Sambuc 179f4a2713aSLionel Sambuc die "could not find clang line\n" if (!defined $line); 180*0a6a1f1dSLionel Sambuc # Strip leading and trailing whitespace characters. 181*0a6a1f1dSLionel Sambuc $line =~ s/^\s+|\s+$//g; 182f4a2713aSLionel Sambuc my @items = quotewords('\s+', 0, $line); 183f4a2713aSLionel Sambuc my $cmd = shift @items; 184f4a2713aSLionel Sambuc die "cannot find 'clang' in 'clang' command\n" if (!($cmd =~ /clang/)); 185f4a2713aSLionel Sambuc return \@items; 186f4a2713aSLionel Sambuc} 187f4a2713aSLionel Sambuc 188f4a2713aSLionel Sambucsub Analyze { 189f4a2713aSLionel Sambuc my ($Clang, $OriginalArgs, $AnalyzeArgs, $Lang, $Output, $Verbose, $HtmlDir, 190f4a2713aSLionel Sambuc $file) = @_; 191f4a2713aSLionel Sambuc 192f4a2713aSLionel Sambuc my @Args = @$OriginalArgs; 193f4a2713aSLionel Sambuc my $Cmd; 194f4a2713aSLionel Sambuc my @CmdArgs; 195f4a2713aSLionel Sambuc my @CmdArgsSansAnalyses; 196f4a2713aSLionel Sambuc 197f4a2713aSLionel Sambuc if ($Lang =~ /header/) { 198f4a2713aSLionel Sambuc exit 0 if (!defined ($Output)); 199f4a2713aSLionel Sambuc $Cmd = 'cp'; 200f4a2713aSLionel Sambuc push @CmdArgs, $file; 201f4a2713aSLionel Sambuc # Remove the PCH extension. 202f4a2713aSLionel Sambuc $Output =~ s/[.]gch$//; 203f4a2713aSLionel Sambuc push @CmdArgs, $Output; 204f4a2713aSLionel Sambuc @CmdArgsSansAnalyses = @CmdArgs; 205f4a2713aSLionel Sambuc } 206f4a2713aSLionel Sambuc else { 207f4a2713aSLionel Sambuc $Cmd = $Clang; 208f4a2713aSLionel Sambuc 209f4a2713aSLionel Sambuc # Create arguments for doing regular parsing. 210f4a2713aSLionel Sambuc my $SyntaxArgs = GetCCArgs("-fsyntax-only", \@Args); 211f4a2713aSLionel Sambuc @CmdArgsSansAnalyses = @$SyntaxArgs; 212f4a2713aSLionel Sambuc 213f4a2713aSLionel Sambuc # Create arguments for doing static analysis. 214f4a2713aSLionel Sambuc if (defined $ResultFile) { 215f4a2713aSLionel Sambuc push @Args, '-o', $ResultFile; 216f4a2713aSLionel Sambuc } 217f4a2713aSLionel Sambuc elsif (defined $HtmlDir) { 218f4a2713aSLionel Sambuc push @Args, '-o', $HtmlDir; 219f4a2713aSLionel Sambuc } 220f4a2713aSLionel Sambuc if ($Verbose) { 221f4a2713aSLionel Sambuc push @Args, "-Xclang", "-analyzer-display-progress"; 222f4a2713aSLionel Sambuc } 223f4a2713aSLionel Sambuc 224f4a2713aSLionel Sambuc foreach my $arg (@$AnalyzeArgs) { 225f4a2713aSLionel Sambuc push @Args, "-Xclang", $arg; 226f4a2713aSLionel Sambuc } 227f4a2713aSLionel Sambuc 228f4a2713aSLionel Sambuc # Display Ubiviz graph? 229f4a2713aSLionel Sambuc if (defined $ENV{'CCC_UBI'}) { 230f4a2713aSLionel Sambuc push @Args, "-Xclang", "-analyzer-viz-egraph-ubigraph"; 231f4a2713aSLionel Sambuc } 232f4a2713aSLionel Sambuc 233f4a2713aSLionel Sambuc my $AnalysisArgs = GetCCArgs("--analyze", \@Args); 234f4a2713aSLionel Sambuc @CmdArgs = @$AnalysisArgs; 235f4a2713aSLionel Sambuc } 236f4a2713aSLionel Sambuc 237f4a2713aSLionel Sambuc my @PrintArgs; 238f4a2713aSLionel Sambuc my $dir; 239f4a2713aSLionel Sambuc 240f4a2713aSLionel Sambuc if ($Verbose) { 241f4a2713aSLionel Sambuc $dir = getcwd(); 242f4a2713aSLionel Sambuc print STDERR "\n[LOCATION]: $dir\n"; 243f4a2713aSLionel Sambuc push @PrintArgs,"'$Cmd'"; 244f4a2713aSLionel Sambuc foreach my $arg (@CmdArgs) { 245f4a2713aSLionel Sambuc push @PrintArgs,"\'$arg\'"; 246f4a2713aSLionel Sambuc } 247f4a2713aSLionel Sambuc } 248f4a2713aSLionel Sambuc if ($Verbose == 1) { 249f4a2713aSLionel Sambuc # We MUST print to stderr. Some clients use the stdout output of 250f4a2713aSLionel Sambuc # gcc for various purposes. 251f4a2713aSLionel Sambuc print STDERR join(' ', @PrintArgs); 252f4a2713aSLionel Sambuc print STDERR "\n"; 253f4a2713aSLionel Sambuc } 254f4a2713aSLionel Sambuc elsif ($Verbose == 2) { 255f4a2713aSLionel Sambuc print STDERR "#SHELL (cd '$dir' && @PrintArgs)\n"; 256f4a2713aSLionel Sambuc } 257f4a2713aSLionel Sambuc 258f4a2713aSLionel Sambuc # Capture the STDERR of clang and send it to a temporary file. 259f4a2713aSLionel Sambuc # Capture the STDOUT of clang and reroute it to ccc-analyzer's STDERR. 260f4a2713aSLionel Sambuc # We save the output file in the 'crashes' directory if clang encounters 261f4a2713aSLionel Sambuc # any problems with the file. 262f4a2713aSLionel Sambuc pipe (FROM_CHILD, TO_PARENT); 263f4a2713aSLionel Sambuc my $pid = fork(); 264f4a2713aSLionel Sambuc if ($pid == 0) { 265f4a2713aSLionel Sambuc close FROM_CHILD; 266f4a2713aSLionel Sambuc open(STDOUT,">&", \*TO_PARENT); 267f4a2713aSLionel Sambuc open(STDERR,">&", \*TO_PARENT); 268f4a2713aSLionel Sambuc exec $Cmd, @CmdArgs; 269f4a2713aSLionel Sambuc } 270f4a2713aSLionel Sambuc 271f4a2713aSLionel Sambuc close TO_PARENT; 272f4a2713aSLionel Sambuc my ($ofh, $ofile) = tempfile("clang_output_XXXXXX", DIR => $HtmlDir); 273f4a2713aSLionel Sambuc 274f4a2713aSLionel Sambuc while (<FROM_CHILD>) { 275f4a2713aSLionel Sambuc print $ofh $_; 276f4a2713aSLionel Sambuc print STDERR $_; 277f4a2713aSLionel Sambuc } 278f4a2713aSLionel Sambuc close $ofh; 279f4a2713aSLionel Sambuc 280f4a2713aSLionel Sambuc waitpid($pid,0); 281f4a2713aSLionel Sambuc close(FROM_CHILD); 282f4a2713aSLionel Sambuc my $Result = $?; 283f4a2713aSLionel Sambuc 284f4a2713aSLionel Sambuc # Did the command die because of a signal? 285f4a2713aSLionel Sambuc if ($ReportFailures) { 286f4a2713aSLionel Sambuc if ($Result & 127 and $Cmd eq $Clang and defined $HtmlDir) { 287f4a2713aSLionel Sambuc ProcessClangFailure($Clang, $Lang, $file, \@CmdArgsSansAnalyses, 288f4a2713aSLionel Sambuc $HtmlDir, "Crash", $ofile); 289f4a2713aSLionel Sambuc } 290f4a2713aSLionel Sambuc elsif ($Result) { 291f4a2713aSLionel Sambuc if ($IncludeParserRejects && !($file =~/conftest/)) { 292f4a2713aSLionel Sambuc ProcessClangFailure($Clang, $Lang, $file, \@CmdArgsSansAnalyses, 293f4a2713aSLionel Sambuc $HtmlDir, $ParserRejects, $ofile); 294f4a2713aSLionel Sambuc } else { 295f4a2713aSLionel Sambuc ProcessClangFailure($Clang, $Lang, $file, \@CmdArgsSansAnalyses, 296f4a2713aSLionel Sambuc $HtmlDir, $OtherError, $ofile); 297f4a2713aSLionel Sambuc } 298f4a2713aSLionel Sambuc } 299f4a2713aSLionel Sambuc else { 300f4a2713aSLionel Sambuc # Check if there were any unhandled attributes. 301f4a2713aSLionel Sambuc if (open(CHILD, $ofile)) { 302f4a2713aSLionel Sambuc my %attributes_not_handled; 303f4a2713aSLionel Sambuc 304f4a2713aSLionel Sambuc # Don't flag warnings about the following attributes that we 305f4a2713aSLionel Sambuc # know are currently not supported by Clang. 306f4a2713aSLionel Sambuc $attributes_not_handled{"cdecl"} = 1; 307f4a2713aSLionel Sambuc 308f4a2713aSLionel Sambuc my $ppfile; 309f4a2713aSLionel Sambuc while (<CHILD>) { 310f4a2713aSLionel Sambuc next if (! /warning: '([^\']+)' attribute ignored/); 311f4a2713aSLionel Sambuc 312f4a2713aSLionel Sambuc # Have we already spotted this unhandled attribute? 313f4a2713aSLionel Sambuc next if (defined $attributes_not_handled{$1}); 314f4a2713aSLionel Sambuc $attributes_not_handled{$1} = 1; 315f4a2713aSLionel Sambuc 316f4a2713aSLionel Sambuc # Get the name of the attribute file. 317f4a2713aSLionel Sambuc my $dir = "$HtmlDir/failures"; 318f4a2713aSLionel Sambuc my $afile = "$dir/attribute_ignored_$1.txt"; 319f4a2713aSLionel Sambuc 320f4a2713aSLionel Sambuc # Only create another preprocessed file if the attribute file 321f4a2713aSLionel Sambuc # doesn't exist yet. 322f4a2713aSLionel Sambuc next if (-e $afile); 323f4a2713aSLionel Sambuc 324f4a2713aSLionel Sambuc # Add this file to the list of files that contained this attribute. 325f4a2713aSLionel Sambuc # Generate a preprocessed file if we haven't already. 326f4a2713aSLionel Sambuc if (!(defined $ppfile)) { 327f4a2713aSLionel Sambuc $ppfile = ProcessClangFailure($Clang, $Lang, $file, 328f4a2713aSLionel Sambuc \@CmdArgsSansAnalyses, 329f4a2713aSLionel Sambuc $HtmlDir, $AttributeIgnored, $ofile); 330f4a2713aSLionel Sambuc } 331f4a2713aSLionel Sambuc 332f4a2713aSLionel Sambuc mkpath $dir; 333f4a2713aSLionel Sambuc open(AFILE, ">$afile"); 334f4a2713aSLionel Sambuc print AFILE "$ppfile\n"; 335f4a2713aSLionel Sambuc close(AFILE); 336f4a2713aSLionel Sambuc } 337f4a2713aSLionel Sambuc close CHILD; 338f4a2713aSLionel Sambuc } 339f4a2713aSLionel Sambuc } 340f4a2713aSLionel Sambuc } 341f4a2713aSLionel Sambuc 342f4a2713aSLionel Sambuc unlink($ofile); 343f4a2713aSLionel Sambuc} 344f4a2713aSLionel Sambuc 345f4a2713aSLionel Sambuc##----------------------------------------------------------------------------## 346f4a2713aSLionel Sambuc# Lookup tables. 347f4a2713aSLionel Sambuc##----------------------------------------------------------------------------## 348f4a2713aSLionel Sambuc 349f4a2713aSLionel Sambucmy %CompileOptionMap = ( 350f4a2713aSLionel Sambuc '-nostdinc' => 0, 351f4a2713aSLionel Sambuc '-include' => 1, 352f4a2713aSLionel Sambuc '-idirafter' => 1, 353f4a2713aSLionel Sambuc '-imacros' => 1, 354f4a2713aSLionel Sambuc '-iprefix' => 1, 355f4a2713aSLionel Sambuc '-iquote' => 1, 356f4a2713aSLionel Sambuc '-isystem' => 1, 357f4a2713aSLionel Sambuc '-iwithprefix' => 1, 358f4a2713aSLionel Sambuc '-iwithprefixbefore' => 1 359f4a2713aSLionel Sambuc); 360f4a2713aSLionel Sambuc 361f4a2713aSLionel Sambucmy %LinkerOptionMap = ( 362f4a2713aSLionel Sambuc '-framework' => 1, 363f4a2713aSLionel Sambuc '-fobjc-link-runtime' => 0 364f4a2713aSLionel Sambuc); 365f4a2713aSLionel Sambuc 366f4a2713aSLionel Sambucmy %CompilerLinkerOptionMap = ( 367f4a2713aSLionel Sambuc '-Wwrite-strings' => 0, 368f4a2713aSLionel Sambuc '-ftrapv-handler' => 1, # specifically call out separated -f flag 369f4a2713aSLionel Sambuc '-mios-simulator-version-min' => 0, # This really has 1 argument, but always has '=' 370f4a2713aSLionel Sambuc '-isysroot' => 1, 371f4a2713aSLionel Sambuc '-arch' => 1, 372f4a2713aSLionel Sambuc '-m32' => 0, 373f4a2713aSLionel Sambuc '-m64' => 0, 374f4a2713aSLionel Sambuc '-stdlib' => 0, # This is really a 1 argument, but always has '=' 375*0a6a1f1dSLionel Sambuc '--sysroot' => 1, 376f4a2713aSLionel Sambuc '-target' => 1, 377f4a2713aSLionel Sambuc '-v' => 0, 378f4a2713aSLionel Sambuc '-mmacosx-version-min' => 0, # This is really a 1 argument, but always has '=' 379f4a2713aSLionel Sambuc '-miphoneos-version-min' => 0 # This is really a 1 argument, but always has '=' 380f4a2713aSLionel Sambuc); 381f4a2713aSLionel Sambuc 382f4a2713aSLionel Sambucmy %IgnoredOptionMap = ( 383f4a2713aSLionel Sambuc '-MT' => 1, # Ignore these preprocessor options. 384f4a2713aSLionel Sambuc '-MF' => 1, 385f4a2713aSLionel Sambuc 386f4a2713aSLionel Sambuc '-fsyntax-only' => 0, 387f4a2713aSLionel Sambuc '-save-temps' => 0, 388f4a2713aSLionel Sambuc '-install_name' => 1, 389f4a2713aSLionel Sambuc '-exported_symbols_list' => 1, 390f4a2713aSLionel Sambuc '-current_version' => 1, 391f4a2713aSLionel Sambuc '-compatibility_version' => 1, 392f4a2713aSLionel Sambuc '-init' => 1, 393f4a2713aSLionel Sambuc '-e' => 1, 394f4a2713aSLionel Sambuc '-seg1addr' => 1, 395f4a2713aSLionel Sambuc '-bundle_loader' => 1, 396f4a2713aSLionel Sambuc '-multiply_defined' => 1, 397f4a2713aSLionel Sambuc '-sectorder' => 3, 398f4a2713aSLionel Sambuc '--param' => 1, 399f4a2713aSLionel Sambuc '-u' => 1, 400f4a2713aSLionel Sambuc '--serialize-diagnostics' => 1 401f4a2713aSLionel Sambuc); 402f4a2713aSLionel Sambuc 403f4a2713aSLionel Sambucmy %LangMap = ( 404*0a6a1f1dSLionel Sambuc 'c' => $IsCXX ? 'c++' : 'c', 405f4a2713aSLionel Sambuc 'cp' => 'c++', 406f4a2713aSLionel Sambuc 'cpp' => 'c++', 407f4a2713aSLionel Sambuc 'cxx' => 'c++', 408f4a2713aSLionel Sambuc 'txx' => 'c++', 409f4a2713aSLionel Sambuc 'cc' => 'c++', 410f4a2713aSLionel Sambuc 'C' => 'c++', 411*0a6a1f1dSLionel Sambuc 'ii' => 'c++-cpp-output', 412*0a6a1f1dSLionel Sambuc 'i' => $IsCXX ? 'c++-cpp-output' : 'c-cpp-output', 413f4a2713aSLionel Sambuc 'm' => 'objective-c', 414f4a2713aSLionel Sambuc 'mi' => 'objective-c-cpp-output', 415*0a6a1f1dSLionel Sambuc 'mm' => 'objective-c++', 416*0a6a1f1dSLionel Sambuc 'mii' => 'objective-c++-cpp-output', 417f4a2713aSLionel Sambuc); 418f4a2713aSLionel Sambuc 419f4a2713aSLionel Sambucmy %UniqueOptions = ( 420f4a2713aSLionel Sambuc '-isysroot' => 0 421f4a2713aSLionel Sambuc); 422f4a2713aSLionel Sambuc 423f4a2713aSLionel Sambuc##----------------------------------------------------------------------------## 424f4a2713aSLionel Sambuc# Languages accepted. 425f4a2713aSLionel Sambuc##----------------------------------------------------------------------------## 426f4a2713aSLionel Sambuc 427f4a2713aSLionel Sambucmy %LangsAccepted = ( 428f4a2713aSLionel Sambuc "objective-c" => 1, 429f4a2713aSLionel Sambuc "c" => 1, 430f4a2713aSLionel Sambuc "c++" => 1, 431*0a6a1f1dSLionel Sambuc "objective-c++" => 1, 432*0a6a1f1dSLionel Sambuc "c-cpp-output" => 1, 433*0a6a1f1dSLionel Sambuc "objective-c-cpp-output" => 1, 434*0a6a1f1dSLionel Sambuc "c++-cpp-output" => 1 435f4a2713aSLionel Sambuc); 436f4a2713aSLionel Sambuc 437f4a2713aSLionel Sambuc##----------------------------------------------------------------------------## 438f4a2713aSLionel Sambuc# Main Logic. 439f4a2713aSLionel Sambuc##----------------------------------------------------------------------------## 440f4a2713aSLionel Sambuc 441f4a2713aSLionel Sambucmy $Action = 'link'; 442f4a2713aSLionel Sambucmy @CompileOpts; 443f4a2713aSLionel Sambucmy @LinkOpts; 444f4a2713aSLionel Sambucmy @Files; 445f4a2713aSLionel Sambucmy $Lang; 446f4a2713aSLionel Sambucmy $Output; 447f4a2713aSLionel Sambucmy %Uniqued; 448f4a2713aSLionel Sambuc 449f4a2713aSLionel Sambuc# Forward arguments to gcc. 450f4a2713aSLionel Sambucmy $Status = system($Compiler,@ARGV); 451f4a2713aSLionel Sambucif (defined $ENV{'CCC_ANALYZER_LOG'}) { 452f4a2713aSLionel Sambuc print STDERR "$Compiler @ARGV\n"; 453f4a2713aSLionel Sambuc} 454f4a2713aSLionel Sambucif ($Status) { exit($Status >> 8); } 455f4a2713aSLionel Sambuc 456f4a2713aSLionel Sambuc# Get the analysis options. 457f4a2713aSLionel Sambucmy $Analyses = $ENV{'CCC_ANALYZER_ANALYSIS'}; 458f4a2713aSLionel Sambuc 459f4a2713aSLionel Sambuc# Get the plugins to load. 460f4a2713aSLionel Sambucmy $Plugins = $ENV{'CCC_ANALYZER_PLUGINS'}; 461f4a2713aSLionel Sambuc 462f4a2713aSLionel Sambuc# Get the store model. 463f4a2713aSLionel Sambucmy $StoreModel = $ENV{'CCC_ANALYZER_STORE_MODEL'}; 464f4a2713aSLionel Sambuc 465f4a2713aSLionel Sambuc# Get the constraints engine. 466f4a2713aSLionel Sambucmy $ConstraintsModel = $ENV{'CCC_ANALYZER_CONSTRAINTS_MODEL'}; 467f4a2713aSLionel Sambuc 468f4a2713aSLionel Sambuc#Get the internal stats setting. 469f4a2713aSLionel Sambucmy $InternalStats = $ENV{'CCC_ANALYZER_INTERNAL_STATS'}; 470f4a2713aSLionel Sambuc 471f4a2713aSLionel Sambuc# Get the output format. 472f4a2713aSLionel Sambucmy $OutputFormat = $ENV{'CCC_ANALYZER_OUTPUT_FORMAT'}; 473f4a2713aSLionel Sambucif (!defined $OutputFormat) { $OutputFormat = "html"; } 474f4a2713aSLionel Sambuc 475*0a6a1f1dSLionel Sambuc# Get the config options. 476*0a6a1f1dSLionel Sambucmy $ConfigOptions = $ENV{'CCC_ANALYZER_CONFIG'}; 477*0a6a1f1dSLionel Sambuc 478f4a2713aSLionel Sambuc# Determine the level of verbosity. 479f4a2713aSLionel Sambucmy $Verbose = 0; 480f4a2713aSLionel Sambucif (defined $ENV{'CCC_ANALYZER_VERBOSE'}) { $Verbose = 1; } 481f4a2713aSLionel Sambucif (defined $ENV{'CCC_ANALYZER_LOG'}) { $Verbose = 2; } 482f4a2713aSLionel Sambuc 483f4a2713aSLionel Sambuc# Get the HTML output directory. 484f4a2713aSLionel Sambucmy $HtmlDir = $ENV{'CCC_ANALYZER_HTML'}; 485f4a2713aSLionel Sambuc 486f4a2713aSLionel Sambucmy %DisabledArchs = ('ppc' => 1, 'ppc64' => 1); 487f4a2713aSLionel Sambucmy %ArchsSeen; 488f4a2713aSLionel Sambucmy $HadArch = 0; 489*0a6a1f1dSLionel Sambucmy $HasSDK = 0; 490f4a2713aSLionel Sambuc 491f4a2713aSLionel Sambuc# Process the arguments. 492f4a2713aSLionel Sambucforeach (my $i = 0; $i < scalar(@ARGV); ++$i) { 493f4a2713aSLionel Sambuc my $Arg = $ARGV[$i]; 494f4a2713aSLionel Sambuc my ($ArgKey) = split /=/,$Arg,2; 495f4a2713aSLionel Sambuc 496f4a2713aSLionel Sambuc # Modes ccc-analyzer supports 497f4a2713aSLionel Sambuc if ($Arg =~ /^-(E|MM?)$/) { $Action = 'preprocess'; } 498f4a2713aSLionel Sambuc elsif ($Arg eq '-c') { $Action = 'compile'; } 499f4a2713aSLionel Sambuc elsif ($Arg =~ /^-print-prog-name/) { exit 0; } 500f4a2713aSLionel Sambuc 501f4a2713aSLionel Sambuc # Specially handle duplicate cases of -arch 502f4a2713aSLionel Sambuc if ($Arg eq "-arch") { 503f4a2713aSLionel Sambuc my $arch = $ARGV[$i+1]; 504f4a2713aSLionel Sambuc # We don't want to process 'ppc' because of Clang's lack of support 505f4a2713aSLionel Sambuc # for Altivec (also some #defines won't likely be defined correctly, etc.) 506f4a2713aSLionel Sambuc if (!(defined $DisabledArchs{$arch})) { $ArchsSeen{$arch} = 1; } 507f4a2713aSLionel Sambuc $HadArch = 1; 508f4a2713aSLionel Sambuc ++$i; 509f4a2713aSLionel Sambuc next; 510f4a2713aSLionel Sambuc } 511f4a2713aSLionel Sambuc 512*0a6a1f1dSLionel Sambuc # On OSX/iOS, record if an SDK path was specified. This 513*0a6a1f1dSLionel Sambuc # is innocuous for other platforms, so the check just happens. 514*0a6a1f1dSLionel Sambuc if ($Arg =~ /^-isysroot/) { 515*0a6a1f1dSLionel Sambuc $HasSDK = 1; 516*0a6a1f1dSLionel Sambuc } 517*0a6a1f1dSLionel Sambuc 518f4a2713aSLionel Sambuc # Options with possible arguments that should pass through to compiler. 519f4a2713aSLionel Sambuc if (defined $CompileOptionMap{$ArgKey}) { 520f4a2713aSLionel Sambuc my $Cnt = $CompileOptionMap{$ArgKey}; 521f4a2713aSLionel Sambuc push @CompileOpts,$Arg; 522f4a2713aSLionel Sambuc while ($Cnt > 0) { ++$i; --$Cnt; push @CompileOpts, $ARGV[$i]; } 523f4a2713aSLionel Sambuc next; 524f4a2713aSLionel Sambuc } 525f4a2713aSLionel Sambuc # Handle the case where there isn't a space after -iquote 526*0a6a1f1dSLionel Sambuc if ($Arg =~ /^-iquote.*/) { 527f4a2713aSLionel Sambuc push @CompileOpts,$Arg; 528f4a2713aSLionel Sambuc next; 529f4a2713aSLionel Sambuc } 530f4a2713aSLionel Sambuc 531f4a2713aSLionel Sambuc # Options with possible arguments that should pass through to linker. 532f4a2713aSLionel Sambuc if (defined $LinkerOptionMap{$ArgKey}) { 533f4a2713aSLionel Sambuc my $Cnt = $LinkerOptionMap{$ArgKey}; 534f4a2713aSLionel Sambuc push @LinkOpts,$Arg; 535f4a2713aSLionel Sambuc while ($Cnt > 0) { ++$i; --$Cnt; push @LinkOpts, $ARGV[$i]; } 536f4a2713aSLionel Sambuc next; 537f4a2713aSLionel Sambuc } 538f4a2713aSLionel Sambuc 539f4a2713aSLionel Sambuc # Options with possible arguments that should pass through to both compiler 540f4a2713aSLionel Sambuc # and the linker. 541f4a2713aSLionel Sambuc if (defined $CompilerLinkerOptionMap{$ArgKey}) { 542f4a2713aSLionel Sambuc my $Cnt = $CompilerLinkerOptionMap{$ArgKey}; 543f4a2713aSLionel Sambuc 544f4a2713aSLionel Sambuc # Check if this is an option that should have a unique value, and if so 545f4a2713aSLionel Sambuc # determine if the value was checked before. 546f4a2713aSLionel Sambuc if ($UniqueOptions{$Arg}) { 547f4a2713aSLionel Sambuc if (defined $Uniqued{$Arg}) { 548f4a2713aSLionel Sambuc $i += $Cnt; 549f4a2713aSLionel Sambuc next; 550f4a2713aSLionel Sambuc } 551f4a2713aSLionel Sambuc $Uniqued{$Arg} = 1; 552f4a2713aSLionel Sambuc } 553f4a2713aSLionel Sambuc 554f4a2713aSLionel Sambuc push @CompileOpts,$Arg; 555f4a2713aSLionel Sambuc push @LinkOpts,$Arg; 556f4a2713aSLionel Sambuc 557f4a2713aSLionel Sambuc while ($Cnt > 0) { 558f4a2713aSLionel Sambuc ++$i; --$Cnt; 559f4a2713aSLionel Sambuc push @CompileOpts, $ARGV[$i]; 560f4a2713aSLionel Sambuc push @LinkOpts, $ARGV[$i]; 561f4a2713aSLionel Sambuc } 562f4a2713aSLionel Sambuc next; 563f4a2713aSLionel Sambuc } 564f4a2713aSLionel Sambuc 565f4a2713aSLionel Sambuc # Ignored options. 566f4a2713aSLionel Sambuc if (defined $IgnoredOptionMap{$ArgKey}) { 567f4a2713aSLionel Sambuc my $Cnt = $IgnoredOptionMap{$ArgKey}; 568f4a2713aSLionel Sambuc while ($Cnt > 0) { 569f4a2713aSLionel Sambuc ++$i; --$Cnt; 570f4a2713aSLionel Sambuc } 571f4a2713aSLionel Sambuc next; 572f4a2713aSLionel Sambuc } 573f4a2713aSLionel Sambuc 574f4a2713aSLionel Sambuc # Compile mode flags. 575f4a2713aSLionel Sambuc if ($Arg =~ /^-[D,I,U](.*)$/) { 576f4a2713aSLionel Sambuc my $Tmp = $Arg; 577f4a2713aSLionel Sambuc if ($1 eq '') { 578f4a2713aSLionel Sambuc # FIXME: Check if we are going off the end. 579f4a2713aSLionel Sambuc ++$i; 580f4a2713aSLionel Sambuc $Tmp = $Arg . $ARGV[$i]; 581f4a2713aSLionel Sambuc } 582f4a2713aSLionel Sambuc push @CompileOpts,$Tmp; 583f4a2713aSLionel Sambuc next; 584f4a2713aSLionel Sambuc } 585f4a2713aSLionel Sambuc 586*0a6a1f1dSLionel Sambuc if ($Arg =~ /^-m.*/) { 587f4a2713aSLionel Sambuc push @CompileOpts,$Arg; 588f4a2713aSLionel Sambuc next; 589f4a2713aSLionel Sambuc } 590f4a2713aSLionel Sambuc 591f4a2713aSLionel Sambuc # Language. 592f4a2713aSLionel Sambuc if ($Arg eq '-x') { 593f4a2713aSLionel Sambuc $Lang = $ARGV[$i+1]; 594f4a2713aSLionel Sambuc ++$i; next; 595f4a2713aSLionel Sambuc } 596f4a2713aSLionel Sambuc 597f4a2713aSLionel Sambuc # Output file. 598f4a2713aSLionel Sambuc if ($Arg eq '-o') { 599f4a2713aSLionel Sambuc ++$i; 600f4a2713aSLionel Sambuc $Output = $ARGV[$i]; 601f4a2713aSLionel Sambuc next; 602f4a2713aSLionel Sambuc } 603f4a2713aSLionel Sambuc 604f4a2713aSLionel Sambuc # Get the link mode. 605f4a2713aSLionel Sambuc if ($Arg =~ /^-[l,L,O]/) { 606f4a2713aSLionel Sambuc if ($Arg eq '-O') { push @LinkOpts,'-O1'; } 607f4a2713aSLionel Sambuc elsif ($Arg eq '-Os') { push @LinkOpts,'-O2'; } 608f4a2713aSLionel Sambuc else { push @LinkOpts,$Arg; } 609f4a2713aSLionel Sambuc 610f4a2713aSLionel Sambuc # Must pass this along for the __OPTIMIZE__ macro 611f4a2713aSLionel Sambuc if ($Arg =~ /^-O/) { push @CompileOpts,$Arg; } 612f4a2713aSLionel Sambuc next; 613f4a2713aSLionel Sambuc } 614f4a2713aSLionel Sambuc 615f4a2713aSLionel Sambuc if ($Arg =~ /^-std=/) { 616f4a2713aSLionel Sambuc push @CompileOpts,$Arg; 617f4a2713aSLionel Sambuc next; 618f4a2713aSLionel Sambuc } 619f4a2713aSLionel Sambuc 620f4a2713aSLionel Sambuc # Get the compiler/link mode. 621f4a2713aSLionel Sambuc if ($Arg =~ /^-F(.+)$/) { 622f4a2713aSLionel Sambuc my $Tmp = $Arg; 623f4a2713aSLionel Sambuc if ($1 eq '') { 624f4a2713aSLionel Sambuc # FIXME: Check if we are going off the end. 625f4a2713aSLionel Sambuc ++$i; 626f4a2713aSLionel Sambuc $Tmp = $Arg . $ARGV[$i]; 627f4a2713aSLionel Sambuc } 628f4a2713aSLionel Sambuc push @CompileOpts,$Tmp; 629f4a2713aSLionel Sambuc push @LinkOpts,$Tmp; 630f4a2713aSLionel Sambuc next; 631f4a2713aSLionel Sambuc } 632f4a2713aSLionel Sambuc 633f4a2713aSLionel Sambuc # Input files. 634f4a2713aSLionel Sambuc if ($Arg eq '-filelist') { 635f4a2713aSLionel Sambuc # FIXME: Make sure we aren't walking off the end. 636f4a2713aSLionel Sambuc open(IN, $ARGV[$i+1]); 637f4a2713aSLionel Sambuc while (<IN>) { s/\015?\012//; push @Files,$_; } 638f4a2713aSLionel Sambuc close(IN); 639f4a2713aSLionel Sambuc ++$i; 640f4a2713aSLionel Sambuc next; 641f4a2713aSLionel Sambuc } 642f4a2713aSLionel Sambuc 643f4a2713aSLionel Sambuc if ($Arg =~ /^-f/) { 644f4a2713aSLionel Sambuc push @CompileOpts,$Arg; 645f4a2713aSLionel Sambuc push @LinkOpts,$Arg; 646f4a2713aSLionel Sambuc next; 647f4a2713aSLionel Sambuc } 648f4a2713aSLionel Sambuc 649f4a2713aSLionel Sambuc # Handle -Wno-. We don't care about extra warnings, but 650f4a2713aSLionel Sambuc # we should suppress ones that we don't want to see. 651f4a2713aSLionel Sambuc if ($Arg =~ /^-Wno-/) { 652f4a2713aSLionel Sambuc push @CompileOpts, $Arg; 653f4a2713aSLionel Sambuc next; 654f4a2713aSLionel Sambuc } 655f4a2713aSLionel Sambuc 656f4a2713aSLionel Sambuc if (!($Arg =~ /^-/)) { 657f4a2713aSLionel Sambuc push @Files, $Arg; 658f4a2713aSLionel Sambuc next; 659f4a2713aSLionel Sambuc } 660f4a2713aSLionel Sambuc} 661f4a2713aSLionel Sambuc 662*0a6a1f1dSLionel Sambuc# If we are on OSX and have an installation where the 663*0a6a1f1dSLionel Sambuc# default SDK is inferred by xcrun use xcrun to infer 664*0a6a1f1dSLionel Sambuc# the SDK. 665*0a6a1f1dSLionel Sambucif (not $HasSDK and $UseXCRUN) { 666*0a6a1f1dSLionel Sambuc my $sdk = `/usr/bin/xcrun --show-sdk-path -sdk macosx`; 667*0a6a1f1dSLionel Sambuc chomp $sdk; 668*0a6a1f1dSLionel Sambuc push @CompileOpts, "-isysroot", $sdk; 669*0a6a1f1dSLionel Sambuc} 670*0a6a1f1dSLionel Sambuc 671f4a2713aSLionel Sambucif ($Action eq 'compile' or $Action eq 'link') { 672f4a2713aSLionel Sambuc my @Archs = keys %ArchsSeen; 673f4a2713aSLionel Sambuc # Skip the file if we don't support the architectures specified. 674f4a2713aSLionel Sambuc exit 0 if ($HadArch && scalar(@Archs) == 0); 675f4a2713aSLionel Sambuc 676f4a2713aSLionel Sambuc foreach my $file (@Files) { 677f4a2713aSLionel Sambuc # Determine the language for the file. 678f4a2713aSLionel Sambuc my $FileLang = $Lang; 679f4a2713aSLionel Sambuc 680f4a2713aSLionel Sambuc if (!defined($FileLang)) { 681f4a2713aSLionel Sambuc # Infer the language from the extension. 682f4a2713aSLionel Sambuc if ($file =~ /[.]([^.]+)$/) { 683f4a2713aSLionel Sambuc $FileLang = $LangMap{$1}; 684f4a2713aSLionel Sambuc } 685f4a2713aSLionel Sambuc } 686f4a2713aSLionel Sambuc 687f4a2713aSLionel Sambuc # FileLang still not defined? Skip the file. 688f4a2713aSLionel Sambuc next if (!defined $FileLang); 689f4a2713aSLionel Sambuc 690f4a2713aSLionel Sambuc # Language not accepted? 691f4a2713aSLionel Sambuc next if (!defined $LangsAccepted{$FileLang}); 692f4a2713aSLionel Sambuc 693f4a2713aSLionel Sambuc my @CmdArgs; 694f4a2713aSLionel Sambuc my @AnalyzeArgs; 695f4a2713aSLionel Sambuc 696f4a2713aSLionel Sambuc if ($FileLang ne 'unknown') { 697f4a2713aSLionel Sambuc push @CmdArgs, '-x', $FileLang; 698f4a2713aSLionel Sambuc } 699f4a2713aSLionel Sambuc 700f4a2713aSLionel Sambuc if (defined $StoreModel) { 701f4a2713aSLionel Sambuc push @AnalyzeArgs, "-analyzer-store=$StoreModel"; 702f4a2713aSLionel Sambuc } 703f4a2713aSLionel Sambuc 704f4a2713aSLionel Sambuc if (defined $ConstraintsModel) { 705f4a2713aSLionel Sambuc push @AnalyzeArgs, "-analyzer-constraints=$ConstraintsModel"; 706f4a2713aSLionel Sambuc } 707f4a2713aSLionel Sambuc 708f4a2713aSLionel Sambuc if (defined $InternalStats) { 709f4a2713aSLionel Sambuc push @AnalyzeArgs, "-analyzer-stats"; 710f4a2713aSLionel Sambuc } 711f4a2713aSLionel Sambuc 712f4a2713aSLionel Sambuc if (defined $Analyses) { 713f4a2713aSLionel Sambuc push @AnalyzeArgs, split '\s+', $Analyses; 714f4a2713aSLionel Sambuc } 715f4a2713aSLionel Sambuc 716f4a2713aSLionel Sambuc if (defined $Plugins) { 717f4a2713aSLionel Sambuc push @AnalyzeArgs, split '\s+', $Plugins; 718f4a2713aSLionel Sambuc } 719f4a2713aSLionel Sambuc 720f4a2713aSLionel Sambuc if (defined $OutputFormat) { 721f4a2713aSLionel Sambuc push @AnalyzeArgs, "-analyzer-output=" . $OutputFormat; 722f4a2713aSLionel Sambuc if ($OutputFormat =~ /plist/) { 723f4a2713aSLionel Sambuc # Change "Output" to be a file. 724f4a2713aSLionel Sambuc my ($h, $f) = tempfile("report-XXXXXX", SUFFIX => ".plist", 725f4a2713aSLionel Sambuc DIR => $HtmlDir); 726f4a2713aSLionel Sambuc $ResultFile = $f; 727*0a6a1f1dSLionel Sambuc # If the HtmlDir is not set, we should clean up the plist files. 728f4a2713aSLionel Sambuc if (!defined $HtmlDir || -z $HtmlDir) { 729f4a2713aSLionel Sambuc $CleanupFile = $f; 730f4a2713aSLionel Sambuc } 731f4a2713aSLionel Sambuc } 732f4a2713aSLionel Sambuc } 733*0a6a1f1dSLionel Sambuc if (defined $ConfigOptions) { 734*0a6a1f1dSLionel Sambuc push @AnalyzeArgs, split '\s+', $ConfigOptions; 735*0a6a1f1dSLionel Sambuc } 736f4a2713aSLionel Sambuc 737f4a2713aSLionel Sambuc push @CmdArgs, @CompileOpts; 738f4a2713aSLionel Sambuc push @CmdArgs, $file; 739f4a2713aSLionel Sambuc 740f4a2713aSLionel Sambuc if (scalar @Archs) { 741f4a2713aSLionel Sambuc foreach my $arch (@Archs) { 742f4a2713aSLionel Sambuc my @NewArgs; 743f4a2713aSLionel Sambuc push @NewArgs, '-arch', $arch; 744f4a2713aSLionel Sambuc push @NewArgs, @CmdArgs; 745f4a2713aSLionel Sambuc Analyze($Clang, \@NewArgs, \@AnalyzeArgs, $FileLang, $Output, 746f4a2713aSLionel Sambuc $Verbose, $HtmlDir, $file); 747f4a2713aSLionel Sambuc } 748f4a2713aSLionel Sambuc } 749f4a2713aSLionel Sambuc else { 750f4a2713aSLionel Sambuc Analyze($Clang, \@CmdArgs, \@AnalyzeArgs, $FileLang, $Output, 751f4a2713aSLionel Sambuc $Verbose, $HtmlDir, $file); 752f4a2713aSLionel Sambuc } 753f4a2713aSLionel Sambuc } 754f4a2713aSLionel Sambuc} 755f4a2713aSLionel Sambuc 756f4a2713aSLionel Sambucexit($Status >> 8); 757