blob: a1308daa8ee6467d9e2606a427bf570cc402dd20 [file] [log] [blame]
Ted Kremenekb0982882008-03-25 22:35:32 +00001#!/usr/bin/env python
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 reduced version of the 'ccc' script that is designed to handle off
11# actual compilation to gcc, but run the code passed to gcc through the
12# static analyzer.
13#
14##===----------------------------------------------------------------------===##
15
16import sys
17import subprocess
18import os
19
20def error(message):
21 print >> sys.stderr, 'ccc: ' + message
22 sys.exit(1)
23
Seo Sanghyeond3894652008-04-04 11:02:21 +000024def quote(arg):
25 if '"' in arg:
26 return repr(arg)
27 return arg
28
Ted Kremenekb0982882008-03-25 22:35:32 +000029def run(args):
Ted Kremenek6e9d38e2008-04-07 23:27:54 +000030 # We MUST print to stderr. Some clients use the stdout output of
31 # gcc for various purposes.
Ted Kremenek33196002008-05-12 23:47:41 +000032 #print >> sys.stderr, ' '.join(map(quote, args))
33 #print >> sys.stderr
Ted Kremenekb0982882008-03-25 22:35:32 +000034 code = subprocess.call(args)
35 if code > 255:
36 code = 1
37 if code:
38 sys.exit(code)
39
Ted Kremenekfe873542008-04-21 21:58:05 +000040def compile(args):
Ted Kremenek6e9d38e2008-04-07 23:27:54 +000041 # We MUST print to stderr. Some clients use the stdout output of
42 # gcc for various purposes.
Ted Kremenek33196002008-05-12 23:47:41 +000043 #print >> sys.stderr, '\n'
Ted Kremenekb0982882008-03-25 22:35:32 +000044 command = 'gcc'.split()
45 run(command + args)
46
47def remove_pch_extension(path):
48 i = path.rfind('.gch')
49 if i < 0:
50 return path
51 return path[:i]
52
Ted Kremenek1262fc42008-05-14 20:10:33 +000053def analyze(clang, args,language,output,files,verbose,htmldir,file,analysis_type):
Ted Kremenek8cb53fb2008-04-03 21:29:11 +000054 if language.find("c++") > 0:
Ted Kremenekb0982882008-03-25 22:35:32 +000055 return
56
Ted Kremenekb0982882008-03-25 22:35:32 +000057 print_args = []
58
Ted Kremenek09c2ad62008-03-31 18:25:05 +000059 if verbose:
Ted Kremenek6e9d38e2008-04-07 23:27:54 +000060 # We MUST print to stderr. Some clients use the stdout output of
61 # gcc for various purposes.
Ted Kremenek09c2ad62008-03-31 18:25:05 +000062 print >> sys.stderr, ' '.join(['\n[LOCATION]:', os.getcwd(), '\n' ])
63 i = 0
64 while i < len(args):
Ted Kremenekb0982882008-03-25 22:35:32 +000065 print_args.append(''.join([ '\'', args[i], '\'' ]))
66 i += 1
Ted Kremeneka9525c92008-05-12 22:07:14 +000067
68
69 RunAnalyzer = 0;
70
Ted Kremenekb0982882008-03-25 22:35:32 +000071 if language.find("header") > 0:
72 target = remove_pch_extension(output)
73 command = 'cp'.split()
74 args = command + files + target.split()
75 else:
Ted Kremenek1262fc42008-05-14 20:10:33 +000076 command = clang.split() + analysis_type.split()
Ted Kremenek69b64422008-03-31 21:20:32 +000077 args = command + args;
Ted Kremeneka9525c92008-05-12 22:07:14 +000078 RunAnalyzer = 1
79
80 if verbose == 2:
81 print >> sys.stderr, '#SHELL (cd ' + os.getcwd() + ' && ' + ' '.join(command + print_args) + ')\n'
Ted Kremeneka9525c92008-05-12 22:07:14 +000082
83 if RunAnalyzer and htmldir is not None:
84 args.append('-o')
85 print_args.append('-o')
86 args.append(htmldir)
87 print_args.append(htmldir)
Ted Kremenek09c2ad62008-03-31 18:25:05 +000088
Ted Kremenek6e9d38e2008-04-07 23:27:54 +000089 if verbose:
90 # We MUST print to stderr. Some clients use the stdout output of
91 # gcc for various purposes.
Ted Kremenek09c2ad62008-03-31 18:25:05 +000092 print >> sys.stderr, ' '.join(command+print_args)
93 print >> sys.stderr, '\n'
Ted Kremeneka9525c92008-05-12 22:07:14 +000094
Ted Kremenek73cb1032008-05-13 17:10:28 +000095 subprocess.call(args)
Ted Kremenekb0982882008-03-25 22:35:32 +000096
97def link(args):
98 command = 'gcc'.split()
99 run(command + args)
100
101def extension(path):
102 return path.split(".")[-1]
103
104def changeextension(path, newext):
105 i = path.rfind('.')
106 if i < 0:
107 return path
108 j = path.rfind('/', 0, i)
109 print path
110 if j < 0:
111 return path[:i] + "." + newext
112 return path[j+1:i] + "." + newext
113
114def inferlanguage(extension):
115 if extension == "c":
116 return "c"
117 elif extension in ["cpp", "cc"]:
118 return "c++"
119 elif extension == "i":
120 return "c-cpp-output"
121 elif extension == "m":
122 return "objective-c"
123 elif extension == "mi":
124 return "objective-c-cpp-output"
125 else:
126 return "unknown"
127
128def main(args):
129 old_args = args
130 action = 'link'
131 output = ''
132 compile_opts = [ ]
133 link_opts = [ ]
134 files = []
135 save_temps = 0
136 language = ''
137
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000138 verbose = 0
Ted Kremenek33196002008-05-12 23:47:41 +0000139 clang = "clang"
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000140
Ted Kremenek33196002008-05-12 23:47:41 +0000141 # Forward to GCC.
142 compile(args)
Ted Kremenek1262fc42008-05-14 20:10:33 +0000143
144 # Set the analyzer flag.
145 analysis_type = os.environ.get('CCC_ANALYZER_ANALYSIS')
146
147 if analysis_type is not None:
148 analysis_type = "-" + analysis_type
149 else:
150 analysis_type = "-checker-cfref"
151
152 # Determine the level of verbosity.
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000153 if os.environ.get('CCC_ANALYZER_VERBOSE') is not None:
Ted Kremeneka9525c92008-05-12 22:07:14 +0000154 verbose = 1
155
156 if os.environ.get('CCC_ANALYZER_LOG') is not None:
157 verbose = 2
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000158
Ted Kremenek1262fc42008-05-14 20:10:33 +0000159 # Determine what clang executable to use.
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000160 clang_env = os.environ.get('CLANG')
161
162 if clang_env is not None:
163 clang = clang_env
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000164
Ted Kremenek1262fc42008-05-14 20:10:33 +0000165 # Get the HTML output directory.
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000166 htmldir = os.environ.get('CCC_ANALYZER_HTML')
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000167
Ted Kremenekb0982882008-03-25 22:35:32 +0000168 i = 0
169 while i < len(args):
170 arg = args[i]
171
172 # Modes ccc supports
173 if arg == '-E':
174 action = 'preprocess'
175 if arg == '-c':
176 action = 'compile'
177 if arg.startswith('-print-prog-name'):
178 action = 'print-prog-name'
179 if arg == '-save-temps':
180 save_temps = 1
181
182 # Options with no arguments that should pass through
183 if arg in ['-v']:
184 compile_opts.append(arg)
185 link_opts.append(arg)
186
187 # Options with one argument that should be ignored
Ted Kremenekd0eef022008-04-21 20:28:01 +0000188 if arg in ['--param', '-u']:
Ted Kremenekb0982882008-03-25 22:35:32 +0000189 i += 1
190
191 # Prefix matches for the compile mode
Ted Kremenekdc343002008-04-25 21:28:20 +0000192 if arg[:2] in ['-D', '-I', '-U', '-F' ]:
Ted Kremenekb0982882008-03-25 22:35:32 +0000193 if not arg[2:]:
194 arg += args[i+1]
195 i += 1
196 compile_opts.append(arg)
Ted Kremenekdc343002008-04-25 21:28:20 +0000197
Ted Kremenekb0982882008-03-25 22:35:32 +0000198 if arg[:5] in ['-std=']:
199 compile_opts.append(arg)
200
Nate Begeman4cd36032008-04-22 04:47:32 +0000201 # Options with one argument that should pass through to compiler
Ted Kremenekdc343002008-04-25 21:28:20 +0000202 if arg in [ '-include', '-idirafter', '-iprefix',
203 '-iquote', '-isystem', '-iwithprefix',
204 '-iwithprefixbefore']:
Ted Kremenekb0982882008-03-25 22:35:32 +0000205 compile_opts.append(arg)
206 compile_opts.append(args[i+1])
207 i += 1
Ted Kremenekdc343002008-04-25 21:28:20 +0000208
209 # Options with no argument that should pass through to compiler
Ted Kremenek73c083c2008-05-01 21:26:22 +0000210 if arg in [ '-nostdinc', '-fobjc-gc-only', '-fobjc-gc' ]:
Ted Kremenekdc343002008-04-25 21:28:20 +0000211 compile_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000212
Nate Begeman4cd36032008-04-22 04:47:32 +0000213 # Options with one argument that should pass through to linker
Ted Kremenek73c083c2008-05-01 21:26:22 +0000214 if arg == '-framework':
Nate Begeman4cd36032008-04-22 04:47:32 +0000215 link_opts.append(arg)
216 link_opts.append(args[i+1])
217 i += 1
218
219 # Options with one argument that should pass through to both
220 if arg in ['-isysroot', '-arch']:
221 compile_opts.append(arg)
222 compile_opts.append(args[i+1])
223 link_opts.append(arg)
224 link_opts.append(args[i+1])
225 i += 1
226
Ted Kremenekb0982882008-03-25 22:35:32 +0000227 # Prefix matches for the link mode
228 if arg[:2] in ['-l', '-L', '-O', '-F']:
229 if arg == '-O': arg = '-O1'
230 if arg == '-Os': arg = '-O2'
231 link_opts.append(arg)
232
Ted Kremenekb0982882008-03-25 22:35:32 +0000233 # Input files
234 if arg == '-filelist':
235 f = open(args[i+1])
236 for line in f:
237 files.append(line.strip())
238 f.close()
239 i += 1
240 if arg == '-x':
241 language = args[i+1]
242 i += 1
243 if arg[0] != '-':
244 files.append(arg)
245
246 # Output file
247 if arg == '-o':
248 output = args[i+1]
249 i += 1
250
251 i += 1
252
253 if action == 'print-prog-name':
254 # assume we can handle everything
255 print sys.argv[0]
256 return
257
258 if not files:
259 error('no input files')
260
Ted Kremenek33196002008-05-12 23:47:41 +0000261 # if action == 'preprocess' or save_temps:
262 # compile(args)
Ted Kremenekb0982882008-03-25 22:35:32 +0000263
264 if action == 'compile' or save_temps:
265 for i, file in enumerate(files):
266 if not language:
267 language = inferlanguage(extension(file))
268 if save_temps and action != "compile":
269 # Need a temporary output file
270 coutput = changeextension(file, "o");
271 files[i] = coutput
272 elif not output:
273 coutput = changeextension(file, "o")
274 else:
275 coutput = output
276 analyze_args = [ file ]
277 if language != 'unknown':
Ted Kremenek7edbce22008-05-12 23:56:50 +0000278 analyze_args = [ '-x', language ] + analyze_args
Ted Kremenekb0982882008-03-25 22:35:32 +0000279 analyze_args = analyze_args + compile_opts
Ted Kremenek1262fc42008-05-14 20:10:33 +0000280 analyze(clang, analyze_args, language, output, files, verbose, htmldir, file, analysis_type)
Ted Kremenek33196002008-05-12 23:47:41 +0000281# compile(args)
Ted Kremenekb0982882008-03-25 22:35:32 +0000282
283
Ted Kremenek33196002008-05-12 23:47:41 +0000284# if action == 'link':
285# link(args)
286# # analyze(link_opts)
Ted Kremenekb0982882008-03-25 22:35:32 +0000287
288if __name__ == '__main__':
289 main(sys.argv[1:])