ccc-analyzer 20 KB

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