blob: 387b52044023196249d026e5f65815c86496a736 [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 = (
105 '-fsyntax-only' => 0,
106 '-save-temps' => 0,
107 '-install_name' => 1,
108 '-exported_symbols_list' => 1,
109 '-current_version' => 1,
110 '-compatibility_version' => 1,
111 '-init' => 1,
112 '-e' => 1,
113 '-seg1addr' => 1,
114 '-bundle_loader' => 1,
115 '-multiply_defined' => 1,
116 '-sectorder' => 3,
117 '--param' => 1,
118 '-u' => 1
119);
120
121my %LangMap = (
122 'c' => 'c',
123 'cpp' => 'c++',
124 'cc' => 'c++',
125 'i' => 'c-cpp-output',
126 'm' => 'objective-c',
127 'mi' => 'objective-c-cpp-output'
128);
129
130##----------------------------------------------------------------------------##
131# Main Logic.
132##----------------------------------------------------------------------------##
133
134my $Action = 'link';
135my @CompileOpts;
136my @LinkOpts;
137my @Files;
138my $Lang;
139my $Output;
140
141# Forward arguments to gcc.
142my $Status = system("gcc",@ARGV);
143if ($Status) { exit($Status); }
144
145# Get the analysis options.
146my $Analyses = $ENV{'CCC_ANALYZER_ANALYSIS'};
147if (!defined($Analyses)) { $Analyses = '-checker-cfref'; }
148
149# Determine the level of verbosity.
150my $Verbose = 0;
151if (defined $ENV{CCC_ANALYZER_VERBOSE}) { $Verbose = 1; }
152if (defined $ENV{CCC_ANALYZER_LOG}) { $Verbose = 2; }
153
154# Determine what clang executable to use.
155my $Clang = $ENV{'CLANG'};
156if (!defined $Clang) { $Clang = 'clang'; }
157
158# Get the HTML output directory.
159my $HtmlDir = $ENV{'CCC_ANALYZER_HTML'};
160
161
162# Process the arguments.
163foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
164 my $Arg = $ARGV[$i];
165
166 # Modes ccc-analyzer supports
167 if ($Arg eq '-E') { $Action = 'preprocess'; }
168 elsif ($Arg eq '-c') { $Action = 'compile'; }
169 elsif ($Arg =~ /^-print-prog-name/) { exit 0; }
Ted Kremenekb0982882008-03-25 22:35:32 +0000170
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000171 # Options with possible arguments that should pass through to compiler.
172 if (defined $CompileOptionMap{$Arg}) {
173 my $Cnt = $CompileOptionMap{$Arg};
174 push @CompileOpts,$Arg;
175 while ($Cnt > 0) { ++$i; --$Cnt; push @CompileOpts, $ARGV[$i]; }
176 next;
177 }
178
179 # Options with possible arguments that should pass through to linker.
180 if (defined $LinkerOptionMap{$Arg}) {
181 my $Cnt = $LinkerOptionMap{$Arg};
182 push @LinkOpts,$Arg;
183 while ($Cnt > 0) { ++$i; --$Cnt; push @LinkOpts, $ARGV[$i]; }
184 next;
185 }
186
187 # Options with possible arguments that should pass through to both compiler
188 # and the linker.
189 if (defined $CompilerLinkerOptionMap{$Arg}) {
190 my $Cnt = $CompilerLinkerOptionMap{$Arg};
191 push @CompileOpts,$Arg;
192 push @LinkOpts,$Arg;
193 while ($Cnt > 0) {
194 ++$i; --$Cnt;
195 push @CompileOpts, $ARGV[$i];
196 push @LinkOpts, $ARGV[$i];
197 }
198 next;
199 }
Ted Kremenek61cd9882008-05-24 15:58:54 +0000200
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000201 # Ignored options.
202 if (defined $IgnoredOptionMap{$Arg}) {
203 my $Cnt = $IgnoredOptionMap{$Arg};
204 while ($Cnt > 0) {
205 ++$i; --$Cnt;
206 }
207 next;
208 }
Ted Kremenek61cd9882008-05-24 15:58:54 +0000209
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000210 # Compile mode flags.
211 if ($Arg =~ /^-[D,I,U](.*)$/) {
212 my $Tmp = $Arg;
213 if ($1 eq '') {
214 # FIXME: Check if we are going off the end.
215 ++$i;
216 $Tmp = $Arg . $ARGV[$i];
217 }
218 push @CompileOpts,$Tmp;
219 next;
220 }
221
222 # Language.
223 if ($Arg eq '-x') {
224 $Lang = $ARGV[$i+1];
225 ++$i; next;
226 }
Ted Kremenek61cd9882008-05-24 15:58:54 +0000227
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000228 # Output file.
229 if ($Arg eq '-o') {
230 ++$i;
231 $Output = $ARGV[$i];
232 next;
233 }
234
235 # Get the link mode.
236 if ($Arg =~ /^-[l,L,O]/) {
237 if ($Arg eq '-O') { push @LinkOpts,'-O1'; }
238 elsif ($Arg eq '-Os') { push @LinkOpts,'-O2'; }
239 else { push @LinkOpts,$Arg; }
240 next;
241 }
242
243 if ($Arg =~ /^-std=/) {
244 push @CompileOpts,$Arg;
245 next;
246 }
247
248# if ($Arg =~ /^-f/) {
249# # FIXME: Not sure if the remaining -fxxxx options have no arguments.
250# push @CompileOpts,$Arg;
251# push @LinkOpts,$Arg; # FIXME: Not sure if these are link opts.
252# }
253
254 # Get the compiler/link mode.
255 if ($Arg =~ /^-F(.+)$/) {
256 my $Tmp = $Arg;
257 if ($1 eq '') {
258 # FIXME: Check if we are going off the end.
259 ++$i;
260 $Tmp = $Arg . $ARGV[$i];
261 }
262 push @CompileOpts,$Tmp;
263 push @LinkOpts,$Tmp;
264 next;
265 }
Ted Kremenek61cd9882008-05-24 15:58:54 +0000266
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000267 # Input files.
268 if ($Arg eq '-filelist') {
269 # FIXME: Make sure we aren't walking off the end.
270 open(IN, $ARGV[$i+1]);
271 while (<IN>) { s/\015?\012//; push @Files,$_; }
272 close(IN);
273 ++$i; next;
274 }
275
276 if (!($Arg =~ /^-/)) {
277 push @Files,$Arg; next;
278 }
279}
Ted Kremenek61cd9882008-05-24 15:58:54 +0000280
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000281if ($Action eq 'compile' or $Action eq 'link') {
282 foreach my $file (@Files) {
283 # Determine the language for the file.
284 my $FileLang = $Lang;
285
286 if (!defined($FileLang)) {
287 # Infer the language from the extension.
288 if ($file =~ /[.]([^.]+)$/) {
289 $FileLang = $LangMap{$1};
290 }
291 }
Ted Kremenek1262fc42008-05-14 20:10:33 +0000292
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000293 next if (!defined $FileLang);
294
295 my @AnalyzeArgs;
296
297 if ($FileLang ne 'unknown') {
298 push @AnalyzeArgs,'-x';
299 push @AnalyzeArgs,$FileLang;
300 }
Ted Kremenekb0982882008-03-25 22:35:32 +0000301
Ted Kremenekfbeeca82008-07-19 06:11:04 +0000302 push @AnalyzeArgs,@CompileOpts;
303 push @AnalyzeArgs,$file;
304
305 Analyze($Clang, \@AnalyzeArgs, $FileLang, $Output,
306 $Verbose, $HtmlDir, $file, $Analyses);
307 }
308}
Ted Kremenekb0982882008-03-25 22:35:32 +0000309