blob: dbf7b6947b8814d90d7eb5b228f057c508f085d8 [file] [log] [blame]
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +00001#!/usr/bin/env perl
2#
3# The LLVM Compiler Infrastructure
4#
5# This file is distributed under the University of Illinois Open Source
6# License. See LICENSE.TXT for details.
7#
8##===----------------------------------------------------------------------===##
9#
10# A script designed to wrap a build so that all calls to gcc are intercepted
11# and piped to the static analyzer.
12#
13##===----------------------------------------------------------------------===##
14
15use strict;
16use warnings;
Ted Kremenek22d6a632008-04-02 20:43:36 +000017use FindBin qw($RealBin);
Ted Kremeneka6e24812008-04-19 18:05:48 +000018use Digest::MD5;
Ted Kremenek7a4648d2008-05-02 22:04:53 +000019use File::Basename;
Ted Kremenek23cfca32008-06-16 22:40:14 +000020use Term::ANSIColor;
21use Term::ANSIColor qw(:constants);
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +000022
23my $Verbose = 0; # Verbose output from this script.
24my $Prog = "scan-build";
Ted Kremenekf4cdf412008-05-23 18:17:05 +000025my $BuildName;
26my $BuildDate;
Ted Kremenek95aa1052008-09-04 17:52:41 +000027my $CXX; # Leave undefined initially.
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +000028
Ted Kremenek0e689382008-09-11 18:17:51 +000029my $TERM = $ENV{'TERM'};
30my $UseColor = (defined $TERM and $TERM eq 'xterm-color' and -t STDOUT
31 and defined $ENV{'SCAN_BUILD_COLOR'});
Ted Kremenek23cfca32008-06-16 22:40:14 +000032
Ted Kremenekb7770c02008-07-15 17:06:13 +000033##----------------------------------------------------------------------------##
34# Diagnostics
35##----------------------------------------------------------------------------##
36
Ted Kremenek23cfca32008-06-16 22:40:14 +000037sub Diag {
38 if ($UseColor) {
39 print BOLD, MAGENTA "$Prog: @_";
40 print RESET;
41 }
42 else {
43 print "$Prog: @_";
44 }
45}
46
Ted Kremenek991c54b2008-08-08 20:46:42 +000047sub DiagCrashes {
48 my $Dir = shift;
49 Diag ("The analyzer crashed on some source files.\n");
Ted Kremenek386c6932008-09-03 17:59:35 +000050 Diag ("Preprocessed versions of crashed files were deposited in '$Dir/crashes'.\n");
Ted Kremenek991c54b2008-08-08 20:46:42 +000051 Diag ("Please consider submitting a bug report using these files:\n");
52 Diag (" http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs\n")
53}
54
Ted Kremenek23cfca32008-06-16 22:40:14 +000055sub DieDiag {
56 if ($UseColor) {
57 print BOLD, RED "$Prog: ";
58 print RESET, RED @_;
59 print RESET;
60 }
61 else {
62 print "$Prog: ", @_;
63 }
64 exit(0);
65}
66
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +000067##----------------------------------------------------------------------------##
Ted Kremenekb7770c02008-07-15 17:06:13 +000068# Some initial preprocessing of Clang options.
69##----------------------------------------------------------------------------##
70
71my $ClangSB = "$RealBin/clang";
72my $Clang = $ClangSB;
73
74if (! -x $ClangSB) {
75 $Clang = "clang";
76}
77
78my %AvailableAnalyses;
79
80# Query clang for analysis options.
Ted Kremenek63c20172008-08-04 17:34:06 +000081open(PIPE, "-|", $Clang, "--help") or
Ted Kremenekb7770c02008-07-15 17:06:13 +000082 DieDiag("Cannot execute '$Clang'");
Ted Kremenek63c20172008-08-04 17:34:06 +000083
Ted Kremenekb7770c02008-07-15 17:06:13 +000084my $FoundAnalysis = 0;
85
86while(<PIPE>) {
87 if ($FoundAnalysis == 0) {
88 if (/Available Source Code Analyses/) {
89 $FoundAnalysis = 1;
90 }
Ted Kremenek991c54b2008-08-08 20:46:42 +000091
Ted Kremenekb7770c02008-07-15 17:06:13 +000092 next;
93 }
94
95 if (/^\s\s\s\s([^\s]+)\s(.+)$/) {
96 next if ($1 =~ /-dump/ or $1 =~ /-view/
97 or $1 =~ /-checker-simple/ or $1 =~ /-warn-uninit/);
98
99 $AvailableAnalyses{$1} = $2;
100 next;
101 }
102
103 last;
104}
105
106close (PIPE);
107
108my %AnalysesDefaultEnabled = (
109 '-warn-dead-stores' => 1,
110 '-checker-cfref' => 1,
Ted Kremenek90125992008-07-15 23:41:32 +0000111 '-warn-objc-methodsigs' => 1,
Ted Kremenekbde3a052008-07-25 20:35:01 +0000112 '-warn-objc-missing-dealloc' => 1,
Ted Kremenek5d443492008-09-18 06:34:16 +0000113 '-warn-objc-unused-ivars' => 1,
114 '-warn-objc-nserror-methods' => 1
Ted Kremenekb7770c02008-07-15 17:06:13 +0000115);
116
117##----------------------------------------------------------------------------##
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000118# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000119##----------------------------------------------------------------------------##
120
Sam Bishopa0e22662008-04-02 03:35:43 +0000121sub GetHTMLRunDir {
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000122
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000123 die "Not enough arguments." if (@_ == 0);
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000124 my $Dir = shift @_;
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000125
126 my $TmpMode = 0;
127 if (!defined $Dir) {
128 $Dir = "/tmp";
129 $TmpMode = 1;
130 }
131
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000132 # Get current date and time.
133
134 my @CurrentTime = localtime();
135
136 my $year = $CurrentTime[5] + 1900;
137 my $day = $CurrentTime[3];
138 my $month = $CurrentTime[4] + 1;
139
Ted Kremenek9d7405f2008-05-14 17:23:56 +0000140 my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000141
142 # Determine the run number.
143
144 my $RunNumber;
145
146 if (-d $Dir) {
147
148 if (! -r $Dir) {
Ted Kremenek23cfca32008-06-16 22:40:14 +0000149 DieDiag("directory '$Dir' exists but is not readable.\n");
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000150 }
151
152 # Iterate over all files in the specified directory.
153
154 my $max = 0;
155
156 opendir(DIR, $Dir);
Ted Kremenek29da6c52008-08-07 17:57:34 +0000157 my @FILES = grep { -d "$Dir/$_" } readdir(DIR);
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000158 closedir(DIR);
159
160 foreach my $f (@FILES) {
161
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000162 # Strip the prefix '$Prog-' if we are dumping files to /tmp.
163 if ($TmpMode) {
164 next if (!($f =~ /^$Prog-(.+)/));
165 $f = $1;
166 }
167
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000168 my @x = split/-/, $f;
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000169
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000170 next if (scalar(@x) != 4);
171 next if ($x[0] != $year);
172 next if ($x[1] != $month);
173 next if ($x[2] != $day);
174
175 if ($x[3] > $max) {
176 $max = $x[3];
177 }
178 }
179
180 $RunNumber = $max + 1;
181 }
182 else {
183
184 if (-x $Dir) {
Ted Kremenek23cfca32008-06-16 22:40:14 +0000185 DieDiag("'$Dir' exists but is not a directory.\n");
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000186 }
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000187
188 if ($TmpMode) {
189 DieDiag("The directory '/tmp' does not exist or cannot be accessed.");
190 }
191
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000192 # $Dir does not exist. It will be automatically created by the
193 # clang driver. Set the run number to 1.
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000194
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000195 $RunNumber = 1;
196 }
197
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000198 die "RunNumber must be defined!" if (!defined $RunNumber);
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000199
200 # Append the run number.
Ted Kremenekfc0898a2008-09-04 23:56:36 +0000201 my $NewDir;
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000202 if ($TmpMode) {
Ted Kremenekfc0898a2008-09-04 23:56:36 +0000203 $NewDir = "$Dir/$Prog-$DateString-$RunNumber";
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000204 }
205 else {
Ted Kremenekfc0898a2008-09-04 23:56:36 +0000206 $NewDir = "$Dir/$DateString-$RunNumber";
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000207 }
Ted Kremenekfc0898a2008-09-04 23:56:36 +0000208 system 'mkdir','-p',$NewDir;
209 return $NewDir;
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000210}
211
Sam Bishopa0e22662008-04-02 03:35:43 +0000212sub SetHtmlEnv {
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000213
214 die "Wrong number of arguments." if (scalar(@_) != 2);
215
216 my $Args = shift;
217 my $Dir = shift;
218
219 die "No build command." if (scalar(@$Args) == 0);
220
221 my $Cmd = $$Args[0];
222
223 if ($Cmd =~ /configure/) {
224 return;
225 }
226
227 if ($Verbose) {
Ted Kremenek23cfca32008-06-16 22:40:14 +0000228 Diag("Emitting reports for this run to '$Dir'.\n");
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000229 }
230
231 $ENV{'CCC_ANALYZER_HTML'} = $Dir;
232}
233
234##----------------------------------------------------------------------------##
Ted Kremenek57cf4462008-04-18 15:09:30 +0000235# ComputeDigest - Compute a digest of the specified file.
236##----------------------------------------------------------------------------##
237
238sub ComputeDigest {
239 my $FName = shift;
Ted Kremenek23cfca32008-06-16 22:40:14 +0000240 DieDiag("Cannot read $FName to compute Digest.\n") if (! -r $FName);
Ted Kremeneka6e24812008-04-19 18:05:48 +0000241
242 # Use Digest::MD5. We don't have to be cryptographically secure. We're
Ted Kremenek7ea02e62008-04-19 18:07:44 +0000243 # just looking for duplicate files that come from a non-malicious source.
244 # We use Digest::MD5 because it is a standard Perl module that should
Ted Kremenek63c20172008-08-04 17:34:06 +0000245 # come bundled on most systems.
Ted Kremenek23cfca32008-06-16 22:40:14 +0000246 open(FILE, $FName) or DieDiag("Cannot open $FName when computing Digest.\n");
Ted Kremeneka6e24812008-04-19 18:05:48 +0000247 binmode FILE;
248 my $Result = Digest::MD5->new->addfile(*FILE)->hexdigest;
249 close(FILE);
250
Ted Kremenek63c20172008-08-04 17:34:06 +0000251 # Return the digest.
Ted Kremeneka6e24812008-04-19 18:05:48 +0000252 return $Result;
Ted Kremenek57cf4462008-04-18 15:09:30 +0000253}
254
255##----------------------------------------------------------------------------##
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000256# UpdatePrefix - Compute the common prefix of files.
257##----------------------------------------------------------------------------##
258
259my $Prefix;
260
261sub UpdatePrefix {
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000262 my $x = shift;
263 my $y = basename($x);
264 $x =~ s/\Q$y\E$//;
265
266 # Ignore /usr, /Library, /System, /Developer
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000267 return if ( $x =~ /^\/usr/ or $x =~ /^\/Library/
268 or $x =~ /^\/System/ or $x =~ /^\/Developer/);
269
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000270 if (!defined $Prefix) {
271 $Prefix = $x;
272 return;
273 }
274
Ted Kremenek20b2bae2008-09-11 21:15:10 +0000275 chop $Prefix while (!($x =~ /^\Q$Prefix/));
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000276}
277
278sub GetPrefix {
279 return $Prefix;
280}
281
282##----------------------------------------------------------------------------##
283# UpdateInFilePath - Update the path in the report file.
284##----------------------------------------------------------------------------##
285
286sub UpdateInFilePath {
287 my $fname = shift;
288 my $regex = shift;
289 my $newtext = shift;
Ted Kremenek63c20172008-08-04 17:34:06 +0000290
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000291 open (RIN, $fname) or die "cannot open $fname";
Ted Kremenek63c20172008-08-04 17:34:06 +0000292 open (ROUT, ">", "$fname.tmp") or die "cannot open $fname.tmp";
293
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000294 while (<RIN>) {
295 s/$regex/$newtext/;
296 print ROUT $_;
297 }
Ted Kremenek63c20172008-08-04 17:34:06 +0000298
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000299 close (ROUT);
300 close (RIN);
Ted Kremenek20161e92008-07-15 20:18:21 +0000301 system("mv", "$fname.tmp", $fname);
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000302}
303
304##----------------------------------------------------------------------------##
Ted Kremenek5744dc22008-04-02 18:03:36 +0000305# ScanFile - Scan a report file for various identifying attributes.
306##----------------------------------------------------------------------------##
307
Ted Kremenek57cf4462008-04-18 15:09:30 +0000308# Sometimes a source file is scanned more than once, and thus produces
309# multiple error reports. We use a cache to solve this problem.
310
311my %AlreadyScanned;
312
Ted Kremenek5744dc22008-04-02 18:03:36 +0000313sub ScanFile {
314
315 my $Index = shift;
316 my $Dir = shift;
317 my $FName = shift;
318
Ted Kremenek57cf4462008-04-18 15:09:30 +0000319 # Compute a digest for the report file. Determine if we have already
320 # scanned a file that looks just like it.
321
322 my $digest = ComputeDigest("$Dir/$FName");
323
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000324 if (defined $AlreadyScanned{$digest}) {
Ted Kremenek57cf4462008-04-18 15:09:30 +0000325 # Redundant file. Remove it.
Ted Kremenek20161e92008-07-15 20:18:21 +0000326 system ("rm", "-f", "$Dir/$FName");
Ted Kremenek57cf4462008-04-18 15:09:30 +0000327 return;
328 }
329
330 $AlreadyScanned{$digest} = 1;
331
Ted Kremenek809709f2008-04-18 16:58:34 +0000332 # At this point the report file is not world readable. Make it happen.
Ted Kremenek20161e92008-07-15 20:18:21 +0000333 system ("chmod", "644", "$Dir/$FName");
Ted Kremenek684bb092008-04-18 15:18:20 +0000334
335 # Scan the report file for tags.
Ted Kremenek23cfca32008-06-16 22:40:14 +0000336 open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
Ted Kremenek5744dc22008-04-02 18:03:36 +0000337
338 my $BugDesc = "";
Ted Kremenek22d6a632008-04-02 20:43:36 +0000339 my $BugFile = "";
340 my $BugPathLength = 1;
341 my $BugLine = 0;
Ted Kremenek5744dc22008-04-02 18:03:36 +0000342
343 while (<IN>) {
344
345 if (/<!-- BUGDESC (.*) -->$/) {
346 $BugDesc = $1;
Ted Kremenek5744dc22008-04-02 18:03:36 +0000347 }
Ted Kremenek22d6a632008-04-02 20:43:36 +0000348 elsif (/<!-- BUGFILE (.*) -->$/) {
349 $BugFile = $1;
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000350 UpdatePrefix($BugFile);
Ted Kremenek22d6a632008-04-02 20:43:36 +0000351 }
352 elsif (/<!-- BUGPATHLENGTH (.*) -->$/) {
353 $BugPathLength = $1;
354 }
355 elsif (/<!-- BUGLINE (.*) -->$/) {
356 $BugLine = $1;
357 }
Ted Kremenek5744dc22008-04-02 18:03:36 +0000358 }
359
360 close(IN);
361
Ted Kremenek22d6a632008-04-02 20:43:36 +0000362 push @$Index,[ $FName, $BugDesc, $BugFile, $BugLine, $BugPathLength ];
363}
364
365##----------------------------------------------------------------------------##
366# CopyJS - Copy JavaScript code to target directory.
367##----------------------------------------------------------------------------##
368
369sub CopyJS {
370
371 my $Dir = shift;
372
Ted Kremenek23cfca32008-06-16 22:40:14 +0000373 DieDiag("Cannot find 'sorttable.js'.\n")
Ted Kremenek22d6a632008-04-02 20:43:36 +0000374 if (! -r "$RealBin/sorttable.js");
375
Ted Kremenek20161e92008-07-15 20:18:21 +0000376 system ("cp", "$RealBin/sorttable.js", "$Dir");
Ted Kremenek22d6a632008-04-02 20:43:36 +0000377
Ted Kremenek23cfca32008-06-16 22:40:14 +0000378 DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n")
Ted Kremenek22d6a632008-04-02 20:43:36 +0000379 if (! -r "$Dir/sorttable.js");
Ted Kremenek5744dc22008-04-02 18:03:36 +0000380}
381
382##----------------------------------------------------------------------------##
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000383# Postprocess - Postprocess the results of an analysis scan.
384##----------------------------------------------------------------------------##
385
Sam Bishopa0e22662008-04-02 03:35:43 +0000386sub Postprocess {
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000387
388 my $Dir = shift;
Ted Kremenek684bb092008-04-18 15:18:20 +0000389 my $BaseDir = shift;
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000390
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000391 die "No directory specified." if (!defined $Dir);
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000392
393 if (! -d $Dir) {
Ted Kremenek23cfca32008-06-16 22:40:14 +0000394 Diag("No bugs found.\n");
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000395 return 0;
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000396 }
397
398 opendir(DIR, $Dir);
Ted Kremenek991c54b2008-08-08 20:46:42 +0000399 my $Crashes = 0;
400 my @files = grep { if ($_ eq "crashes") { $Crashes++; }
401 /^report-.*\.html$/; } readdir(DIR);
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000402 closedir(DIR);
403
Ted Kremenek991c54b2008-08-08 20:46:42 +0000404 if (scalar(@files) == 0 and $Crashes == 0) {
Ted Kremenek23cfca32008-06-16 22:40:14 +0000405 Diag("Removing directory '$Dir' because it contains no reports.\n");
Ted Kremenek20161e92008-07-15 20:18:21 +0000406 system ("rm", "-fR", $Dir);
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000407 return 0;
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000408 }
Ted Kremenek5744dc22008-04-02 18:03:36 +0000409
Ted Kremenek991c54b2008-08-08 20:46:42 +0000410 # Scan each report file and build an index.
411 my @Index;
Ted Kremenek5744dc22008-04-02 18:03:36 +0000412 foreach my $file (@files) { ScanFile(\@Index, $Dir, $file); }
413
Ted Kremenekd52e4252008-08-25 20:45:07 +0000414 # Scan the crashes directory and use the information in the .info files
415 # to update the common prefix directory.
416 if (-d "$Dir/crashes") {
417 opendir(DIR, "$Dir/crashes");
418 my @files = grep { /[.]info$/; } readdir(DIR);
419 closedir(DIR);
420 foreach my $file (@files) {
421 open IN, "$Dir/crashes/$file" or DieDiag("cannot open $file\n");
422 my $Path = <IN>;
423 if (defined $Path) { UpdatePrefix($Path); }
424 close IN;
425 }
426 }
427
Ted Kremenek63c20172008-08-04 17:34:06 +0000428 # Generate an index.html file.
429 my $FName = "$Dir/index.html";
430 open(OUT, ">", $FName) or DieDiag("Cannot create file '$FName'\n");
Ted Kremenek5744dc22008-04-02 18:03:36 +0000431
Ted Kremenek6e6eff72008-04-15 20:47:02 +0000432 # Print out the header.
433
Ted Kremenek5744dc22008-04-02 18:03:36 +0000434print OUT <<ENDTEXT;
435<html>
436<head>
Ted Kremenek7f8a3252008-04-02 18:42:49 +0000437<style type="text/css">
438 body { color:#000000; background-color:#ffffff }
Ted Kremenek22d6a632008-04-02 20:43:36 +0000439 body { font-family: Helvetica, sans-serif; font-size:9pt }
Ted Kremenek7f8a3252008-04-02 18:42:49 +0000440 h1 { font-size:12pt }
Ted Kremenek991c54b2008-08-08 20:46:42 +0000441 table thead {
Ted Kremenek22d6a632008-04-02 20:43:36 +0000442 background-color:#eee; color:#666666;
443 font-weight: bold; cursor: default;
Ted Kremenekbba1cf52008-04-03 05:50:51 +0000444 text-align:center;
445 border-top: 2px solid #000000;
446 border-bottom: 2px solid #000000;
447 font-weight: bold; font-family: Verdana
448 }
Ted Kremenek991c54b2008-08-08 20:46:42 +0000449 table { border: 1px #000000 solid }
450 table { border-collapse: collapse; border-spacing: 0px }
Ted Kremenek7f8a3252008-04-02 18:42:49 +0000451 td { border-bottom: 1px #000000 dotted }
Ted Kremenek22d6a632008-04-02 20:43:36 +0000452 td { padding:5px; padding-left:8px; padding-right:8px }
Ted Kremenekd8c6d0c2008-04-07 23:50:07 +0000453 td { text-align:left; font-size:9pt }
Ted Kremenek22d6a632008-04-02 20:43:36 +0000454 td.View { padding-left: 10px }
Ted Kremenek7f8a3252008-04-02 18:42:49 +0000455</style>
Ted Kremenek22d6a632008-04-02 20:43:36 +0000456<script src="sorttable.js"></script>
Ted Kremenek6e6eff72008-04-15 20:47:02 +0000457<script language='javascript' type="text/javascript">
458function SetDisplay(RowClass, DisplayVal)
459{
460 var Rows = document.getElementsByTagName("tr");
461 for ( var i = 0 ; i < Rows.length; ++i ) {
462 if (Rows[i].className == RowClass) {
463 Rows[i].style.display = DisplayVal;
464 }
465 }
466}
467
468function ToggleDisplay(CheckButton, ClassName) {
Ted Kremenek6e6eff72008-04-15 20:47:02 +0000469 if (CheckButton.checked) {
470 SetDisplay(ClassName, "");
471 }
472 else {
473 SetDisplay(ClassName, "none");
474 }
475}
476</script>
477</head>
478<body>
479ENDTEXT
480
Ted Kremenek991c54b2008-08-08 20:46:42 +0000481 if (scalar(@files)) {
482 # Print out the summary table.
483 my %Totals;
Ted Kremenek6e6eff72008-04-15 20:47:02 +0000484
Ted Kremenek991c54b2008-08-08 20:46:42 +0000485 for my $row ( @Index ) {
486 #my $bug_type = lc($row->[1]);
487 my $bug_type = ($row->[1]);
Ted Kremenek6e6eff72008-04-15 20:47:02 +0000488
Ted Kremenek991c54b2008-08-08 20:46:42 +0000489 if (!defined $Totals{$bug_type}) { $Totals{$bug_type} = 1; }
490 else { $Totals{$bug_type}++; }
Ted Kremenek6e6eff72008-04-15 20:47:02 +0000491 }
Ted Kremenek991c54b2008-08-08 20:46:42 +0000492
493 print OUT "<h3>Bug Summary</h3>";
494
495 if (defined $BuildName) {
496 print OUT "\n<p>Results in this analysis run are based on analyzer build <b>$BuildName</b>.</p>\n"
Ted Kremenek6e6eff72008-04-15 20:47:02 +0000497 }
Ted Kremenekf4cdf412008-05-23 18:17:05 +0000498
Ted Kremenek6e6eff72008-04-15 20:47:02 +0000499print OUT <<ENDTEXT;
Ted Kremenek6e6eff72008-04-15 20:47:02 +0000500<table class="sortable">
501<tr>
502 <td>Bug Type</td>
503 <td>Quantity</td>
Ted Kremenek2645c772008-07-07 16:58:44 +0000504 <td class="sorttable_nosort">Display?</td>
Ted Kremenek6e6eff72008-04-15 20:47:02 +0000505</tr>
506ENDTEXT
507
Ted Kremenek991c54b2008-08-08 20:46:42 +0000508 for my $key ( sort { $a cmp $b } keys %Totals ) {
509 my $x = lc($key);
510 $x =~ s/[ ,'"]+/_/g;
511 print OUT "<tr><td>$key</td><td>$Totals{$key}</td><td><input type=\"checkbox\" onClick=\"ToggleDisplay(this,'bt_$x');\" checked/></td></tr>\n";
512 }
Ted Kremenek6e6eff72008-04-15 20:47:02 +0000513
514 # Print out the table of errors.
515
516print OUT <<ENDTEXT;
517</table>
518<h3>Reports</h3>
Ted Kremenek22d6a632008-04-02 20:43:36 +0000519<table class="sortable">
Ted Kremenek7f8a3252008-04-02 18:42:49 +0000520<tr>
Ted Kremenek88a96d62008-07-07 17:23:32 +0000521 <td class="sorttable_sorted">Bug Type<span id="sorttable_sortfwdind">&nbsp;&#x25BE;</span>
Ted Kremenekbba1cf52008-04-03 05:50:51 +0000522 <td>File</td>
523 <td>Line</td>
524 <td>Path Length</td>
Ted Kremenek2645c772008-07-07 16:58:44 +0000525 <td class="sorttable_nosort"></td>
Ted Kremenek7f8a3252008-04-02 18:42:49 +0000526</tr>
Ted Kremenek5744dc22008-04-02 18:03:36 +0000527ENDTEXT
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000528
Ted Kremenek991c54b2008-08-08 20:46:42 +0000529 my $prefix = GetPrefix();
530 my $regex;
531 my $InFileRegex;
532 my $InFilePrefix = "File:</td><td>";
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000533
Ted Kremenek991c54b2008-08-08 20:46:42 +0000534 if (defined $prefix) {
535 $regex = qr/^\Q$prefix\E/is;
536 $InFileRegex = qr/\Q$InFilePrefix$prefix\E/is;
537 }
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000538
Ted Kremenek991c54b2008-08-08 20:46:42 +0000539 for my $row ( sort { $a->[1] cmp $b->[1] } @Index ) {
Ted Kremenek5744dc22008-04-02 18:03:36 +0000540
Ted Kremenek991c54b2008-08-08 20:46:42 +0000541 my $x = lc($row->[1]);
542 $x =~ s/[ ,'"]+/_/g;
Ted Kremenek6e6eff72008-04-15 20:47:02 +0000543
Ted Kremenek991c54b2008-08-08 20:46:42 +0000544 print OUT "<tr class=\"bt_$x\">\n";
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000545
Ted Kremenek991c54b2008-08-08 20:46:42 +0000546 my $ReportFile = $row->[0];
Ted Kremenek5744dc22008-04-02 18:03:36 +0000547
Ted Kremenek991c54b2008-08-08 20:46:42 +0000548 print OUT " <td class=\"DESC\">";
549 #print OUT lc($row->[1]);
550 print OUT $row->[1];
551 print OUT "</td>\n";
Ted Kremenek5744dc22008-04-02 18:03:36 +0000552
Ted Kremenek991c54b2008-08-08 20:46:42 +0000553 # Update the file prefix.
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000554
Ted Kremenek991c54b2008-08-08 20:46:42 +0000555 my $fname = $row->[2];
556 if (defined $regex) {
557 $fname =~ s/$regex//;
558 UpdateInFilePath("$Dir/$ReportFile", $InFileRegex, $InFilePrefix)
559 }
Ted Kremenek3e56e0b2008-05-02 23:40:49 +0000560
Ted Kremenek991c54b2008-08-08 20:46:42 +0000561 print OUT "<td>$fname</td>\n";
Ted Kremenek7a4648d2008-05-02 22:04:53 +0000562
Ted Kremenek991c54b2008-08-08 20:46:42 +0000563 # Print the rest of the columns.
564 for my $j ( 3 .. $#{$row} ) {
565 print OUT "<td>$row->[$j]</td>\n"
566 }
Ted Kremenek7f8a3252008-04-02 18:42:49 +0000567
Ted Kremenek991c54b2008-08-08 20:46:42 +0000568 # Emit the "View" link.
569 print OUT " <td class=\"View\"><a href=\"$ReportFile#EndPath\">View</a></td>\n";
Ted Kremenek3cea9ee2008-07-30 17:58:08 +0000570
Ted Kremenek991c54b2008-08-08 20:46:42 +0000571 # End the row.
572 print OUT "</tr>\n";
573 }
574
575 print OUT "</table>\n";
576 }
577
578 if ($Crashes) {
579 # Read the crash directory for files.
580 opendir(DIR, "$Dir/crashes");
581 my @files = grep { /[.]info$/ } readdir(DIR);
582 closedir(DIR);
583
584 if (scalar(@files)) {
585 print OUT <<ENDTEXT;
Ted Kremenek5d31f832008-08-18 18:38:29 +0000586<h3>Analyzer Failures</h3>
Ted Kremenek991c54b2008-08-08 20:46:42 +0000587
Ted Kremenek5d31f832008-08-18 18:38:29 +0000588<p>The analyzer had problems processing the following files:</p>
Ted Kremenek991c54b2008-08-08 20:46:42 +0000589
590<table>
Ted Kremenek9f9b1fd2008-09-12 22:49:36 +0000591<thead><tr><td>Problem</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>
Ted Kremenek991c54b2008-08-08 20:46:42 +0000592ENDTEXT
593
594 foreach my $file (sort @files) {
595 $file =~ /(.+).info$/;
596 # Get the preprocessed file.
597 my $ppfile = $1;
598 # Open the info file and get the name of the source file.
599 open (INFO, "$Dir/crashes/$file") or
600 die "Cannot open $Dir/crashes/$file\n";
601 my $srcfile = <INFO>;
Ted Kremenek5d31f832008-08-18 18:38:29 +0000602 chomp $srcfile;
603 my $problem = <INFO>;
604 chomp $problem;
Ted Kremenek991c54b2008-08-08 20:46:42 +0000605 close (INFO);
606 # Print the information in the table.
Ted Kremenekd52e4252008-08-25 20:45:07 +0000607 my $prefix = GetPrefix();
Ted Kremenek9f9b1fd2008-09-12 22:49:36 +0000608 if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
609 print OUT "<tr><td>$problem</td><td>$srcfile</td><td><a href=\"crashes/$ppfile\">$ppfile</a></td><td><a href=\"crashes/$ppfile.stderr.txt\">$ppfile.stderr.txt</a></td></tr>\n";
Ted Kremenek991c54b2008-08-08 20:46:42 +0000610 }
611
612 print OUT <<ENDTEXT;
613</table>
614<p>Please consider submitting preprocessed files as <a href="http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs">bug reports</a>.</p>
615ENDTEXT
616 }
Ted Kremenek5744dc22008-04-02 18:03:36 +0000617 }
618
Ted Kremenek991c54b2008-08-08 20:46:42 +0000619 print OUT "</body></html>\n";
Ted Kremenek5744dc22008-04-02 18:03:36 +0000620 close(OUT);
Ted Kremenek22d6a632008-04-02 20:43:36 +0000621 CopyJS($Dir);
Ted Kremenek20161e92008-07-15 20:18:21 +0000622
623 # Make sure $Dir and $BaseDir are world readable/executable.
624 system("chmod", "755", $Dir);
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000625 if (defined $BaseDir) { system("chmod", "755", $BaseDir); }
Ted Kremenek20161e92008-07-15 20:18:21 +0000626
Ted Kremenek23cfca32008-06-16 22:40:14 +0000627 my $Num = scalar(@Index);
Ted Kremenek150c2122008-07-11 19:15:05 +0000628 Diag("$Num bugs found.\n");
629 if ($Num > 0 && -r "$Dir/index.html") {
630 Diag("Open '$Dir/index.html' to examine bug reports.\n");
631 }
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000632
Ted Kremenek991c54b2008-08-08 20:46:42 +0000633 DiagCrashes($Dir) if ($Crashes);
634
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000635 return $Num;
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000636}
637
638##----------------------------------------------------------------------------##
Ted Kremenekdab11102008-04-02 04:43:42 +0000639# RunBuildCommand - Run the build command.
640##----------------------------------------------------------------------------##
641
Ted Kremenek6b628982008-04-30 23:47:12 +0000642sub AddIfNotPresent {
643 my $Args = shift;
644 my $Arg = shift;
645 my $found = 0;
646
647 foreach my $k (@$Args) {
648 if ($k eq $Arg) {
649 $found = 1;
650 last;
651 }
652 }
653
654 if ($found == 0) {
655 push @$Args, $Arg;
656 }
657}
658
Ted Kremenekdab11102008-04-02 04:43:42 +0000659sub RunBuildCommand {
660
661 my $Args = shift;
Ted Kremenek7442ca62008-04-02 16:04:51 +0000662 my $IgnoreErrors = shift;
Ted Kremenekdab11102008-04-02 04:43:42 +0000663 my $Cmd = $Args->[0];
Ted Kremenek6195c372008-06-02 21:52:47 +0000664 my $CCAnalyzer = shift;
Ted Kremenekdab11102008-04-02 04:43:42 +0000665
Ted Kremenek3301cb12008-06-30 18:18:16 +0000666 # Get only the part of the command after the last '/'.
667 if ($Cmd =~ /\/([^\/]+)$/) {
668 $Cmd = $1;
669 }
670
Ted Kremenek63c20172008-08-04 17:34:06 +0000671 if ($Cmd eq "gcc" or $Cmd eq "cc" or $Cmd eq "llvm-gcc"
672 or $Cmd eq "ccc-analyzer") {
Ted Kremenekdab11102008-04-02 04:43:42 +0000673 shift @$Args;
Ted Kremenek6195c372008-06-02 21:52:47 +0000674 unshift @$Args, $CCAnalyzer;
Ted Kremenekdab11102008-04-02 04:43:42 +0000675 }
Ted Kremenek7442ca62008-04-02 16:04:51 +0000676 elsif ($IgnoreErrors) {
677 if ($Cmd eq "make" or $Cmd eq "gmake") {
Ted Kremenek6b628982008-04-30 23:47:12 +0000678 AddIfNotPresent($Args,"-k");
Ted Kremenek8912b542008-05-13 21:28:02 +0000679 AddIfNotPresent($Args,"-i");
Ted Kremenek7442ca62008-04-02 16:04:51 +0000680 }
681 elsif ($Cmd eq "xcodebuild") {
Ted Kremenek6b628982008-04-30 23:47:12 +0000682 AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
Ted Kremenek7442ca62008-04-02 16:04:51 +0000683 }
Ted Kremenek6b628982008-04-30 23:47:12 +0000684 }
685
Ted Kremenek6b628982008-04-30 23:47:12 +0000686 if ($Cmd eq "xcodebuild") {
Ted Kremenekcfd4c7b2008-05-23 22:18:16 +0000687 # Disable distributed builds for xcodebuild.
Ted Kremenek6b628982008-04-30 23:47:12 +0000688 AddIfNotPresent($Args,"-nodistribute");
Ted Kremenekcfd4c7b2008-05-23 22:18:16 +0000689
690 # Disable PCH files until clang supports them.
691 AddIfNotPresent($Args,"GCC_PRECOMPILE_PREFIX_HEADER=NO");
Ted Kremenek915e9722008-05-27 23:18:07 +0000692
693 # When 'CC' is set, xcodebuild uses it to do all linking, even if we are
694 # linking C++ object files. Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
695 # when linking such files.
Ted Kremenek95aa1052008-09-04 17:52:41 +0000696 die if (!defined $CXX);
697 my $LDPLUSPLUS = `which $CXX`;
Ted Kremenek915e9722008-05-27 23:18:07 +0000698 $LDPLUSPLUS =~ s/\015?\012//; # strip newlines
699 $ENV{'LDPLUSPLUS'} = $LDPLUSPLUS;
Ted Kremenek6b628982008-04-30 23:47:12 +0000700 }
Ted Kremenekdab11102008-04-02 04:43:42 +0000701
Ted Kremenek5a4ddaf2008-08-25 20:10:45 +0000702 return (system(@$Args) >> 8);
Ted Kremenekdab11102008-04-02 04:43:42 +0000703}
704
Ted Kremenekdab11102008-04-02 04:43:42 +0000705##----------------------------------------------------------------------------##
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000706# DisplayHelp - Utility function to display all help options.
707##----------------------------------------------------------------------------##
708
Sam Bishopa0e22662008-04-02 03:35:43 +0000709sub DisplayHelp {
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000710
Ted Kremenek5744dc22008-04-02 18:03:36 +0000711print <<ENDTEXT;
Sam Bishopa0e22662008-04-02 03:35:43 +0000712USAGE: $Prog [options] <build command> [build options]
Ted Kremenek2b74ab62008-04-01 21:22:03 +0000713
Ted Kremenekf4cdf412008-05-23 18:17:05 +0000714ENDTEXT
715
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000716 if (defined $BuildName) {
Ted Kremenekf4cdf412008-05-23 18:17:05 +0000717 print "ANALYZER BUILD: $BuildName ($BuildDate)\n\n";
718 }
719
720print <<ENDTEXT;
Ted Kremenek2b74ab62008-04-01 21:22:03 +0000721OPTIONS:
722
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000723 -o - Target directory for HTML report files. Subdirectories
Sam Bishopa0e22662008-04-02 03:35:43 +0000724 will be created as needed to represent separate "runs" of
Ted Kremenek2b74ab62008-04-01 21:22:03 +0000725 the analyzer. If this option is not specified, a directory
726 is created in /tmp to store the reports.
Ted Kremenek1262fc42008-05-14 20:10:33 +0000727
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000728 -h - Display this message.
729 --help
Ted Kremenek1262fc42008-05-14 20:10:33 +0000730
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000731 -k - Add a "keep on going" option to the specified build command.
732 --keep-going This option currently supports make and xcodebuild.
Ted Kremenekf02e8db2008-04-02 16:41:25 +0000733 This is a convenience option; one can specify this
734 behavior directly using build options.
Ted Kremenek2b74ab62008-04-01 21:22:03 +0000735
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000736 --status-bugs - By default, the exit status of $Prog is the same as the
737 executed build command. Specifying this option causes the
738 exit status of $Prog to be 1 if it found potential bugs
739 and 0 otherwise.
Ted Kremenek2b74ab62008-04-01 21:22:03 +0000740
Ted Kremenek386c6932008-09-03 17:59:35 +0000741 --use-cc [compiler path] - By default, $Prog uses 'gcc' to compile and link
742 --use-cc=[compiler path] your C and Objective-C code. Use this option
743 to specify an alternate compiler.
744
745 --use-c++ [compiler path] - By default, $Prog uses 'g++' to compile and link
746 --use-c++=[compiler path] your C++ and Objective-C++ code. Use this option
747 to specify an alternate compiler.
Ted Kremenekf17ef3c2008-08-21 21:47:09 +0000748
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000749 -v - Verbose output from $Prog and the analyzer.
Ted Kremenek386c6932008-09-03 17:59:35 +0000750 A second and third '-v' increases verbosity.
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000751
752 -V - View analysis results in a web browser when the build
753 --view completes.
Ted Kremenek7f8a3252008-04-02 18:42:49 +0000754
Ted Kremenekb7770c02008-07-15 17:06:13 +0000755
Ted Kremenek386c6932008-09-03 17:59:35 +0000756AVAILABLE ANALYSES (multiple analyses may be specified):
Ted Kremenekd52e4252008-08-25 20:45:07 +0000757
758ENDTEXT
Ted Kremenekb7770c02008-07-15 17:06:13 +0000759
760 foreach my $Analysis (sort keys %AvailableAnalyses) {
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000761 if (defined $AnalysesDefaultEnabled{$Analysis}) {
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000762 print " (+)";
Ted Kremenekb7770c02008-07-15 17:06:13 +0000763 }
764 else {
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000765 print " ";
Ted Kremenekb7770c02008-07-15 17:06:13 +0000766 }
767
768 print " $Analysis $AvailableAnalyses{$Analysis}\n";
769 }
770
771print <<ENDTEXT
772
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000773 NOTE: "(+)" indicates that an analysis is enabled by default unless one
774 or more analysis options are specified
Ted Kremenekb7770c02008-07-15 17:06:13 +0000775
Ted Kremenek2b74ab62008-04-01 21:22:03 +0000776BUILD OPTIONS
777
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000778 You can specify any build option acceptable to the build command.
Ted Kremenek39eefde2008-04-02 16:47:27 +0000779
Ted Kremenek5744dc22008-04-02 18:03:36 +0000780EXAMPLE
Ted Kremenek2b74ab62008-04-01 21:22:03 +0000781
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000782 $Prog -o /tmp/myhtmldir make -j4
Ted Kremenek2b74ab62008-04-01 21:22:03 +0000783
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000784 The above example causes analysis reports to be deposited into
785 a subdirectory of "/tmp/myhtmldir" and to run "make" with the "-j4" option.
786 A different subdirectory is created each time $Prog analyzes a project.
787 The analyzer should support most parallel builds, but not distributed builds.
Ted Kremenek2b74ab62008-04-01 21:22:03 +0000788
789ENDTEXT
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000790}
791
792##----------------------------------------------------------------------------##
793# Process command-line arguments.
794##----------------------------------------------------------------------------##
795
796my $HtmlDir; # Parent directory to store HTML files.
797my $IgnoreErrors = 0; # Ignore build errors.
Ted Kremenek7f8a3252008-04-02 18:42:49 +0000798my $ViewResults = 0; # View results when the build terminates.
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000799my $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
Ted Kremenekb7770c02008-07-15 17:06:13 +0000800my @AnalysesToRun;
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000801
802if (!@ARGV) {
803 DisplayHelp();
Sam Bishopa0e22662008-04-02 03:35:43 +0000804 exit 1;
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000805}
806
807while (@ARGV) {
808
809 # Scan for options we recognize.
810
811 my $arg = $ARGV[0];
812
Sam Bishop2f2418e2008-04-03 14:29:47 +0000813 if ($arg eq "-h" or $arg eq "--help") {
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000814 DisplayHelp();
Sam Bishopa0e22662008-04-02 03:35:43 +0000815 exit 0;
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000816 }
817
Ted Kremenekfc1d3402008-08-04 18:15:26 +0000818 if (defined $AvailableAnalyses{$arg}) {
Ted Kremenek1262fc42008-05-14 20:10:33 +0000819 shift @ARGV;
Ted Kremenekb7770c02008-07-15 17:06:13 +0000820 push @AnalysesToRun, $arg;
Ted Kremenek1262fc42008-05-14 20:10:33 +0000821 next;
822 }
823
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000824 if ($arg eq "-o") {
825 shift @ARGV;
826
827 if (!@ARGV) {
Ted Kremenek23cfca32008-06-16 22:40:14 +0000828 DieDiag("'-o' option requires a target directory name.\n");
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000829 }
830
831 $HtmlDir = shift @ARGV;
832 next;
833 }
834
Ted Kremenek2b74ab62008-04-01 21:22:03 +0000835 if ($arg eq "-k" or $arg eq "--keep-going") {
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000836 shift @ARGV;
837 $IgnoreErrors = 1;
838 next;
839 }
840
Ted Kremenekf17ef3c2008-08-21 21:47:09 +0000841 if ($arg =~ /^--use-cc(=(.+))?$/) {
842 shift @ARGV;
843 my $cc;
844
845 if ($2 eq "") {
846 if (!@ARGV) {
847 DieDiag("'--use-cc' option requires a compiler executable name.\n");
848 }
849 $cc = shift @ARGV;
850 }
851 else {
852 $cc = $2;
853 }
854
855 $ENV{"CCC_CC"} = $cc;
856 next;
857 }
858
Ted Kremenek386c6932008-09-03 17:59:35 +0000859 if ($arg =~ /^--use-c[+][+](=(.+))?$/) {
860 shift @ARGV;
861
862 if ($2 eq "") {
863 if (!@ARGV) {
864 DieDiag("'--use-c++' option requires a compiler executable name.\n");
865 }
866 $CXX = shift @ARGV;
867 }
868 else {
869 $CXX = $2;
870 }
871 next;
872 }
873
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000874 if ($arg eq "-v") {
875 shift @ARGV;
876 $Verbose++;
877 next;
878 }
879
Ted Kremenek7f8a3252008-04-02 18:42:49 +0000880 if ($arg eq "-V" or $arg eq "--view") {
881 shift @ARGV;
882 $ViewResults = 1;
883 next;
884 }
885
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000886 if ($arg eq "--status-bugs") {
887 shift @ARGV;
888 $ExitStatusFoundBugs = 1;
889 next;
890 }
891
Ted Kremenek23cfca32008-06-16 22:40:14 +0000892 DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
Ted Kremenek0062ad42008-04-02 16:35:01 +0000893
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000894 last;
895}
896
897if (!@ARGV) {
Ted Kremenek23cfca32008-06-16 22:40:14 +0000898 Diag("No build command specified.\n\n");
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000899 DisplayHelp();
Sam Bishopa0e22662008-04-02 03:35:43 +0000900 exit 1;
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000901}
902
Ted Kremenek386c6932008-09-03 17:59:35 +0000903
904
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000905# Determine the output directory for the HTML reports.
Ted Kremenek684bb092008-04-18 15:18:20 +0000906my $BaseDir = $HtmlDir;
Sam Bishopa0e22662008-04-02 03:35:43 +0000907$HtmlDir = GetHTMLRunDir($HtmlDir);
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000908
909# Set the appropriate environment variables.
Sam Bishopa0e22662008-04-02 03:35:43 +0000910SetHtmlEnv(\@ARGV, $HtmlDir);
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000911
Ted Kremenek0b6c1532008-04-08 20:22:12 +0000912my $Cmd = "$RealBin/ccc-analyzer";
913
Ted Kremenek23cfca32008-06-16 22:40:14 +0000914DieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n")
Ted Kremenek0b6c1532008-04-08 20:22:12 +0000915 if (! -x $Cmd);
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000916
Ted Kremenekb7770c02008-07-15 17:06:13 +0000917if (! -x $ClangSB) {
918 Diag("'clang' executable not found in '$RealBin'.\n");
919 Diag("Using 'clang' from path.\n");
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000920}
Ted Kremenek0b6c1532008-04-08 20:22:12 +0000921
Ted Kremenek95aa1052008-09-04 17:52:41 +0000922if (defined $CXX) {
923 $ENV{'CXX'} = $CXX;
924}
925else {
926 $CXX = 'g++'; # This variable is used by other parts of scan-build
927 # that need to know a default C++ compiler to fall back to.
928}
929
Ted Kremenek4f4b17d2008-04-03 20:08:18 +0000930$ENV{'CC'} = $Cmd;
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000931$ENV{'CLANG'} = $Clang;
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000932
933if ($Verbose >= 2) {
934 $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
935}
936
Ted Kremeneka9525c92008-05-12 22:07:14 +0000937if ($Verbose >= 3) {
938 $ENV{'CCC_ANALYZER_LOG'} = 1;
939}
940
Ted Kremenek90125992008-07-15 23:41:32 +0000941if (scalar(@AnalysesToRun) == 0) {
942 foreach my $key (keys %AnalysesDefaultEnabled) {
943 push @AnalysesToRun,$key;
944 }
Ted Kremenek01006782008-07-02 23:16:10 +0000945}
Ted Kremenek1262fc42008-05-14 20:10:33 +0000946
Ted Kremenek90125992008-07-15 23:41:32 +0000947$ENV{'CCC_ANALYZER_ANALYSIS'} = join ' ',@AnalysesToRun;
948
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000949# Run the build.
Ted Kremenek5656a982008-07-15 17:09:28 +0000950my $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd);
Ted Kremenek9cc8c2c2008-04-01 20:47:38 +0000951
952# Postprocess the HTML directory.
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000953my $NumBugs = Postprocess($HtmlDir, $BaseDir);
Ted Kremenek7f8a3252008-04-02 18:42:49 +0000954
955if ($ViewResults and -r "$HtmlDir/index.html") {
956 # Only works on Mac OS X (for now).
957 print "Viewing analysis results: '$HtmlDir/index.html'\n";
Ted Kremenek20161e92008-07-15 20:18:21 +0000958 system("open", "$HtmlDir/index.html");
Ted Kremenek7f8a3252008-04-02 18:42:49 +0000959}
Ted Kremenek5656a982008-07-15 17:09:28 +0000960
Ted Kremenek363dc3f2008-07-15 22:03:09 +0000961if ($ExitStatusFoundBugs) {
962 exit 1 if ($NumBugs > 0);
963 exit 0;
964}
965
Ted Kremenek5656a982008-07-15 17:09:28 +0000966exit $ExitStatus;
967