blob: 2c81b0f32b998b79a91b097d26cd11bc9dde5a9a [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"
Ted Kremenek48921c82008-05-14 20:20:46 +0000125 elif extension == "s":
Ted Kremenekbfd6a3f2008-05-14 20:17:17 +0000126 return "skip"
Ted Kremenekb0982882008-03-25 22:35:32 +0000127 else:
128 return "unknown"
129
130def main(args):
131 old_args = args
132 action = 'link'
133 output = ''
134 compile_opts = [ ]
135 link_opts = [ ]
136 files = []
137 save_temps = 0
138 language = ''
139
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000140 verbose = 0
Ted Kremenek33196002008-05-12 23:47:41 +0000141 clang = "clang"
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000142
Ted Kremenek33196002008-05-12 23:47:41 +0000143 # Forward to GCC.
144 compile(args)
Ted Kremenek1262fc42008-05-14 20:10:33 +0000145
146 # Set the analyzer flag.
147 analysis_type = os.environ.get('CCC_ANALYZER_ANALYSIS')
148
149 if analysis_type is not None:
150 analysis_type = "-" + analysis_type
151 else:
152 analysis_type = "-checker-cfref"
153
154 # Determine the level of verbosity.
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000155 if os.environ.get('CCC_ANALYZER_VERBOSE') is not None:
Ted Kremeneka9525c92008-05-12 22:07:14 +0000156 verbose = 1
157
158 if os.environ.get('CCC_ANALYZER_LOG') is not None:
159 verbose = 2
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000160
Ted Kremenek1262fc42008-05-14 20:10:33 +0000161 # Determine what clang executable to use.
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000162 clang_env = os.environ.get('CLANG')
163
164 if clang_env is not None:
165 clang = clang_env
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000166
Ted Kremenek1262fc42008-05-14 20:10:33 +0000167 # Get the HTML output directory.
Ted Kremenek26681e82008-05-14 20:26:52 +0000168 htmldir = None
169
170 if analysis_type == "-checker-cfref":
171 htmldir = os.environ.get('CCC_ANALYZER_HTML')
172
173 # Process the arguments.
Ted Kremenekb0982882008-03-25 22:35:32 +0000174 i = 0
175 while i < len(args):
176 arg = args[i]
177
178 # Modes ccc supports
179 if arg == '-E':
180 action = 'preprocess'
181 if arg == '-c':
182 action = 'compile'
183 if arg.startswith('-print-prog-name'):
184 action = 'print-prog-name'
185 if arg == '-save-temps':
186 save_temps = 1
187
188 # Options with no arguments that should pass through
189 if arg in ['-v']:
190 compile_opts.append(arg)
191 link_opts.append(arg)
192
193 # Options with one argument that should be ignored
Ted Kremenekd0eef022008-04-21 20:28:01 +0000194 if arg in ['--param', '-u']:
Ted Kremenekb0982882008-03-25 22:35:32 +0000195 i += 1
196
197 # Prefix matches for the compile mode
Ted Kremenekdc343002008-04-25 21:28:20 +0000198 if arg[:2] in ['-D', '-I', '-U', '-F' ]:
Ted Kremenekb0982882008-03-25 22:35:32 +0000199 if not arg[2:]:
200 arg += args[i+1]
201 i += 1
202 compile_opts.append(arg)
Ted Kremenekdc343002008-04-25 21:28:20 +0000203
Ted Kremenekb0982882008-03-25 22:35:32 +0000204 if arg[:5] in ['-std=']:
205 compile_opts.append(arg)
206
Nate Begeman4cd36032008-04-22 04:47:32 +0000207 # Options with one argument that should pass through to compiler
Ted Kremenekdc343002008-04-25 21:28:20 +0000208 if arg in [ '-include', '-idirafter', '-iprefix',
209 '-iquote', '-isystem', '-iwithprefix',
210 '-iwithprefixbefore']:
Ted Kremenekb0982882008-03-25 22:35:32 +0000211 compile_opts.append(arg)
212 compile_opts.append(args[i+1])
213 i += 1
Ted Kremenekdc343002008-04-25 21:28:20 +0000214
215 # Options with no argument that should pass through to compiler
Ted Kremenek73c083c2008-05-01 21:26:22 +0000216 if arg in [ '-nostdinc', '-fobjc-gc-only', '-fobjc-gc' ]:
Ted Kremenekdc343002008-04-25 21:28:20 +0000217 compile_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000218
Nate Begeman4cd36032008-04-22 04:47:32 +0000219 # Options with one argument that should pass through to linker
Ted Kremenek73c083c2008-05-01 21:26:22 +0000220 if arg == '-framework':
Nate Begeman4cd36032008-04-22 04:47:32 +0000221 link_opts.append(arg)
222 link_opts.append(args[i+1])
223 i += 1
224
225 # Options with one argument that should pass through to both
226 if arg in ['-isysroot', '-arch']:
227 compile_opts.append(arg)
228 compile_opts.append(args[i+1])
229 link_opts.append(arg)
230 link_opts.append(args[i+1])
231 i += 1
232
Ted Kremenekb0982882008-03-25 22:35:32 +0000233 # Prefix matches for the link mode
234 if arg[:2] in ['-l', '-L', '-O', '-F']:
235 if arg == '-O': arg = '-O1'
236 if arg == '-Os': arg = '-O2'
237 link_opts.append(arg)
238
Ted Kremenekb0982882008-03-25 22:35:32 +0000239 # Input files
240 if arg == '-filelist':
241 f = open(args[i+1])
242 for line in f:
243 files.append(line.strip())
244 f.close()
245 i += 1
246 if arg == '-x':
247 language = args[i+1]
248 i += 1
249 if arg[0] != '-':
250 files.append(arg)
251
252 # Output file
253 if arg == '-o':
254 output = args[i+1]
255 i += 1
256
257 i += 1
258
259 if action == 'print-prog-name':
260 # assume we can handle everything
261 print sys.argv[0]
262 return
263
264 if not files:
265 error('no input files')
266
Ted Kremenek33196002008-05-12 23:47:41 +0000267 # if action == 'preprocess' or save_temps:
268 # compile(args)
Ted Kremenekb0982882008-03-25 22:35:32 +0000269
270 if action == 'compile' or save_temps:
271 for i, file in enumerate(files):
272 if not language:
273 language = inferlanguage(extension(file))
Ted Kremenekbfd6a3f2008-05-14 20:17:17 +0000274 if language == "skip":
275 continue
276
Ted Kremenekb0982882008-03-25 22:35:32 +0000277 if save_temps and action != "compile":
278 # Need a temporary output file
279 coutput = changeextension(file, "o");
280 files[i] = coutput
281 elif not output:
282 coutput = changeextension(file, "o")
283 else:
284 coutput = output
285 analyze_args = [ file ]
286 if language != 'unknown':
Ted Kremenek7edbce22008-05-12 23:56:50 +0000287 analyze_args = [ '-x', language ] + analyze_args
Ted Kremenekb0982882008-03-25 22:35:32 +0000288 analyze_args = analyze_args + compile_opts
Ted Kremenek1262fc42008-05-14 20:10:33 +0000289 analyze(clang, analyze_args, language, output, files, verbose, htmldir, file, analysis_type)
Ted Kremenek33196002008-05-12 23:47:41 +0000290# compile(args)
Ted Kremenekb0982882008-03-25 22:35:32 +0000291
292
Ted Kremenek33196002008-05-12 23:47:41 +0000293# if action == 'link':
294# link(args)
295# # analyze(link_opts)
Ted Kremenekb0982882008-03-25 22:35:32 +0000296
297if __name__ == '__main__':
298 main(sys.argv[1:])