blob: 1659c53a5ad04be73f56c40502964549c2e24eaa [file] [log] [blame]
Ted Kremenekfbeeca82008-07-19 06:11:04 +00001#!/usr/bin/env perl
Ted Kremenekb0982882008-03-25 22:35:32 +00002#
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#
Ted Kremenekfbeeca82008-07-19 06:11:04 +000010# A script designed to interpose between the build system and gcc. It invokes
11# both gcc and the static analyzer.
Ted Kremenekb0982882008-03-25 22:35:32 +000012#
13##===----------------------------------------------------------------------===##
14
Ted Kremenekfbeeca82008-07-19 06:11:04 +000015use strict;
16use warnings;
17use Cwd;
Ted Kremenekb0982882008-03-25 22:35:32 +000018
Ted Kremenekfbeeca82008-07-19 06:11:04 +000019##----------------------------------------------------------------------------##
20# Running the analyzer.
21##----------------------------------------------------------------------------##
Ted Kremenekb0982882008-03-25 22:35:32 +000022
Ted Kremenekfbeeca82008-07-19 06:11:04 +000023sub Analyze {
24 my ($Clang, $Args, $Lang, $Output, $Verbose, $HtmlDir, $file, $Analyses) = @_;
Seo Sanghyeond3894652008-04-04 11:02:21 +000025
Ted Kremenekfbeeca82008-07-19 06:11:04 +000026 # Skip anything related to C++.
27 return if ($Lang =~ /c[+][+]/);
Ted Kremenekb0982882008-03-25 22:35:32 +000028
Ted Kremenekfbeeca82008-07-19 06:11:04 +000029 my $RunAnalyzer = 0;
30 my $Cmd;
31 my @CmdArgs;
Ted Kremenek61cd9882008-05-24 15:58:54 +000032
Ted Kremenekfbeeca82008-07-19 06:11:04 +000033 if ($Lang =~ /header/) {
34 exit 0 if (!defined ($Output));
35 $Cmd = 'cp';
36 push @CmdArgs,$file;
37 # Remove the PCH extension.
38 $Output =~ s/[.]gch$//;
39 push @CmdArgs,$Output;
40 }
41 else {
42 $Cmd = $Clang;
43 push @CmdArgs,(split /\s/,$Analyses);
44 push @CmdArgs,'-DIBOutlet=__attribute__((iboutlet))';
45 push @CmdArgs,@$Args;
46 $RunAnalyzer = 1;
47 }
48
49 my @PrintArgs;
50 my $dir;
51
52 if ($Verbose) {
53 $dir = getcwd();
54 print STDERR "\n[LOCATION]: $dir\n";
55 push @PrintArgs,"'$Cmd'";
56 foreach my $arg (@CmdArgs) { push @PrintArgs,"\'$arg\'"; }
57 }
58
59 if ($Verbose == 1) {
Ted Kremenek61cd9882008-05-24 15:58:54 +000060 # We MUST print to stderr. Some clients use the stdout output of
61 # gcc for various purposes.
Ted Kremenekfbeeca82008-07-19 06:11:04 +000062 print STDERR join(' ',@PrintArgs);
63 print STDERR "\n";
64 }
65 elsif ($Verbose == 2) {
66 print STDERR "#SHELL (cd '$dir' && @PrintArgs)\n";
67 }
Ted Kremenek61cd9882008-05-24 15:58:54 +000068
Ted Kremenekfbeeca82008-07-19 06:11:04 +000069 if ($RunAnalyzer and defined($HtmlDir)) {
70 push @CmdArgs,'-o';
71 push @CmdArgs,$HtmlDir;
72 }
Ted Kremenek61cd9882008-05-24 15:58:54 +000073
Ted Kremenekfbeeca82008-07-19 06:11:04 +000074 system $Cmd,@CmdArgs;
75}
Ted Kremenek61cd9882008-05-24 15:58:54 +000076
Ted Kremenekfbeeca82008-07-19 06:11:04 +000077##----------------------------------------------------------------------------##
78# Lookup tables.
79##----------------------------------------------------------------------------##
80
81my %CompileOptionMap = (
82 '-nostdinc' => 0,
83 '-fobjc-gc-only' => 0,
84 '-fobjc-gc' => 0,
85 '-include' => 1,
86 '-idirafter' => 1,
87 '-iprefix' => 1,
88 '-iquote' => 1,
89 '-isystem' => 1,
90 '-iwithprefix' => 1,
91 '-iwithprefixbefore' => 1
92);
93
94my %LinkerOptionMap = (
95 '-framework' => 1
96);
97
98my %CompilerLinkerOptionMap = (
99 '-isysroot' => 1,
100 '-arch' => 1,
101 '-v' => 0
102);
103
104my %IgnoredOptionMap = (
Ted Kremenek94026092008-07-24 03:52:21 +0000105 '-MT' => 1, # Ignore these preprocessor options.
106 '-MF' => 1,
107
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000108 '-fsyntax-only' => 0,
109 '-save-temps' => 0,
110 '-install_name' => 1,
111 '-exported_symbols_list' => 1,
112 '-current_version' => 1,
113 '-compatibility_version' => 1,
114 '-init' => 1,
115 '-e' => 1,
116 '-seg1addr' => 1,
117 '-bundle_loader' => 1,
118 '-multiply_defined' => 1,
119 '-sectorder' => 3,
120 '--param' => 1,
121 '-u' => 1
122);
123
124my %LangMap = (
125 'c' => 'c',
126 'cpp' => 'c++',
127 'cc' => 'c++',
128 'i' => 'c-cpp-output',
129 'm' => 'objective-c',
130 'mi' => 'objective-c-cpp-output'
131);
132
133##----------------------------------------------------------------------------##
134# Main Logic.
135##----------------------------------------------------------------------------##
136
137my $Action = 'link';
138my @CompileOpts;
139my @LinkOpts;
140my @Files;
141my $Lang;
142my $Output;
143
144# Forward arguments to gcc.
145my $Status = system("gcc",@ARGV);
146if ($Status) { exit($Status); }
147
148# Get the analysis options.
149my $Analyses = $ENV{'CCC_ANALYZER_ANALYSIS'};
150if (!defined($Analyses)) { $Analyses = '-checker-cfref'; }
151
152# Determine the level of verbosity.
153my $Verbose = 0;
154if (defined $ENV{CCC_ANALYZER_VERBOSE}) { $Verbose = 1; }
155if (defined $ENV{CCC_ANALYZER_LOG}) { $Verbose = 2; }
156
157# Determine what clang executable to use.
158my $Clang = $ENV{'CLANG'};
159if (!defined $Clang) { $Clang = 'clang'; }
160
161# Get the HTML output directory.
162my $HtmlDir = $ENV{'CCC_ANALYZER_HTML'};
163
164
165# Process the arguments.
166foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
167 my $Arg = $ARGV[$i];
168
169 # Modes ccc-analyzer supports
170 if ($Arg eq '-E') { $Action = 'preprocess'; }
171 elsif ($Arg eq '-c') { $Action = 'compile'; }
172 elsif ($Arg =~ /^-print-prog-name/) { exit 0; }
Ted Kremenekb0982882008-03-25 22:35:32 +0000173
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000174 # Options with possible arguments that should pass through to compiler.
175 if (defined $CompileOptionMap{$Arg}) {
176 my $Cnt = $CompileOptionMap{$Arg};
177 push @CompileOpts,$Arg;
178 while ($Cnt > 0) { ++$i; --$Cnt; push @CompileOpts, $ARGV[$i]; }
179 next;
180 }
181
182 # Options with possible arguments that should pass through to linker.
183 if (defined $LinkerOptionMap{$Arg}) {
184 my $Cnt = $LinkerOptionMap{$Arg};
185 push @LinkOpts,$Arg;
186 while ($Cnt > 0) { ++$i; --$Cnt; push @LinkOpts, $ARGV[$i]; }
187 next;
188 }
189
190 # Options with possible arguments that should pass through to both compiler
191 # and the linker.
192 if (defined $CompilerLinkerOptionMap{$Arg}) {
193 my $Cnt = $CompilerLinkerOptionMap{$Arg};
194 push @CompileOpts,$Arg;
195 push @LinkOpts,$Arg;
196 while ($Cnt > 0) {
197 ++$i; --$Cnt;
198 push @CompileOpts, $ARGV[$i];
199 push @LinkOpts, $ARGV[$i];
200 }
201 next;
202 }
Ted Kremenek61cd9882008-05-24 15:58:54 +0000203
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000204 # Ignored options.
205 if (defined $IgnoredOptionMap{$Arg}) {
206 my $Cnt = $IgnoredOptionMap{$Arg};
207 while ($Cnt > 0) {
208 ++$i; --$Cnt;
209 }
210 next;
211 }
Ted Kremenek61cd9882008-05-24 15:58:54 +0000212
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000213 # Compile mode flags.
214 if ($Arg =~ /^-[D,I,U](.*)$/) {
215 my $Tmp = $Arg;
216 if ($1 eq '') {
217 # FIXME: Check if we are going off the end.
218 ++$i;
219 $Tmp = $Arg . $ARGV[$i];
220 }
221 push @CompileOpts,$Tmp;
222 next;
223 }
224
225 # Language.
226 if ($Arg eq '-x') {
227 $Lang = $ARGV[$i+1];
228 ++$i; next;
229 }
Ted Kremenek61cd9882008-05-24 15:58:54 +0000230
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000231 # Output file.
232 if ($Arg eq '-o') {
233 ++$i;
234 $Output = $ARGV[$i];
235 next;
236 }
237
238 # Get the link mode.
239 if ($Arg =~ /^-[l,L,O]/) {
240 if ($Arg eq '-O') { push @LinkOpts,'-O1'; }
241 elsif ($Arg eq '-Os') { push @LinkOpts,'-O2'; }
242 else { push @LinkOpts,$Arg; }
243 next;
244 }
245
246 if ($Arg =~ /^-std=/) {
247 push @CompileOpts,$Arg;
248 next;
249 }
250
251# if ($Arg =~ /^-f/) {
252# # FIXME: Not sure if the remaining -fxxxx options have no arguments.
253# push @CompileOpts,$Arg;
254# push @LinkOpts,$Arg; # FIXME: Not sure if these are link opts.
255# }
256
257 # Get the compiler/link mode.
258 if ($Arg =~ /^-F(.+)$/) {
259 my $Tmp = $Arg;
260 if ($1 eq '') {
261 # FIXME: Check if we are going off the end.
262 ++$i;
263 $Tmp = $Arg . $ARGV[$i];
264 }
265 push @CompileOpts,$Tmp;
266 push @LinkOpts,$Tmp;
267 next;
268 }
Ted Kremenek61cd9882008-05-24 15:58:54 +0000269
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000270 # Input files.
271 if ($Arg eq '-filelist') {
272 # FIXME: Make sure we aren't walking off the end.
273 open(IN, $ARGV[$i+1]);
274 while (<IN>) { s/\015?\012//; push @Files,$_; }
275 close(IN);
276 ++$i; next;
277 }
278
279 if (!($Arg =~ /^-/)) {
280 push @Files,$Arg; next;
281 }
282}
Ted Kremenek61cd9882008-05-24 15:58:54 +0000283
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000284if ($Action eq 'compile' or $Action eq 'link') {
285 foreach my $file (@Files) {
286 # Determine the language for the file.
287 my $FileLang = $Lang;
288
289 if (!defined($FileLang)) {
290 # Infer the language from the extension.
291 if ($file =~ /[.]([^.]+)$/) {
292 $FileLang = $LangMap{$1};
293 }
294 }
Ted Kremenek1262fc42008-05-14 20:10:33 +0000295
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000296 next if (!defined $FileLang);
297
298 my @AnalyzeArgs;
299
300 if ($FileLang ne 'unknown') {
301 push @AnalyzeArgs,'-x';
302 push @AnalyzeArgs,$FileLang;
303 }
Ted Kremenekb0982882008-03-25 22:35:32 +0000304
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000305 push @AnalyzeArgs,@CompileOpts;
306 push @AnalyzeArgs,$file;
307
308 Analyze($Clang, \@AnalyzeArgs, $FileLang, $Output,
309 $Verbose, $HtmlDir, $file, $Analyses);
310 }
311}
Ted Kremenekb0982882008-03-25 22:35:32 +0000312